BIND 10 master, updated. c0672d18dc8709e15a175e781a5d690a281f6d19 [master] Merge branch 'trac2282merge'

BIND 10 source code commits bind10-changes at lists.isc.org
Wed Sep 26 18:21:13 UTC 2012


The branch, master has been updated
       via  c0672d18dc8709e15a175e781a5d690a281f6d19 (commit)
       via  28c929309ce6200a388e97b5cb89e81f2e061a6f (commit)
       via  a3a63ba5ca940d188dc28a4cd2db63d908ec3e1b (commit)
       via  7298821ace8f33cd683dc52856e7272e52eef589 (commit)
       via  8660a77ac739583b013c502a903ea9cdd979ae7e (commit)
       via  7e2522e4177ca26bd511395be02f35c96335bcd0 (commit)
       via  59c096cda4f3fbe9f3744c6cbe01497c909b4f06 (commit)
       via  d0a83e52167113c55010a44d69e8b540d9bbd00b (commit)
       via  6a0721cb9647ea09a7ca40174dee6de870829cc5 (commit)
       via  4735853efc9554536e607a3431631348ea2d0c49 (commit)
       via  f9a376ab22abb84377f24846f66b49c58469fe17 (commit)
       via  f569d3269831e8ad74e8f5c4d2e84d38e524c979 (commit)
       via  c7060ccf5e4ec41ee12e08e66f410fe14199c545 (commit)
       via  730fd2f2de14300227720977b581c421088dfec7 (commit)
       via  55f7ce059f925a531c9f0fe9adad18c1a941dec6 (commit)
       via  42dc5ad3e7eed5f53d2d38b6683b7a9b427c1a1d (commit)
       via  09ccd7c1ec01fd8d30270b2d8ee37a4e5e4962b1 (commit)
       via  e5222941c0cc25a5580eab58390dcf62ea2278a8 (commit)
       via  51cbca9e606137fcdad96a99824f27809701afcc (commit)
       via  12d5f67f3e58ab09f8369b4218baa2c8a40e2b9a (commit)
       via  1830f45cda873932566b1eacfb15f5f6170cf916 (commit)
       via  593cc7dda0802634b12373f0215b6033e1791118 (commit)
       via  736bcacc37bde8182160fbf5b4c8191a1846373e (commit)
       via  8c2ea7566498c8b3f826a85316ae63f0d57e80b0 (commit)
       via  babcf09173d27ad28f53d911d1908c7375fd4e22 (commit)
       via  ab51eb2f65a390b98b5601f8e7bf5bd6634e4ad6 (commit)
       via  493a2b3d0b3c494aced54e2778595618ec6f5100 (commit)
       via  89476cd22065c79ba1c7dd48a29f0fc958917b39 (commit)
       via  00bbd50bb77e798708891f177003ad1d01bf9dbe (commit)
       via  e016cdf94cb3377f4e186e4f175ef89eb382089f (commit)
       via  4a8a4d185ddee401aeed95f9f51d443d725c4d5f (commit)
       via  117a2ea8230671c17c8011cdd2f0b747eadbec01 (commit)
       via  c60790ce9bd68bb155ea77f5f6629f9f754ef9c7 (commit)
       via  07b53c2297ed4bbb167fda55b43b70575208f0d3 (commit)
       via  e13c2404bea730239b16f5b74142e7364fa739aa (commit)
       via  360b20fadb0530d2cb069f428c09fa6320d941ad (commit)
       via  6c447559f19adc0e040a6a6f44c06dffcf3ce0ff (commit)
       via  40d4887c7d706c0a27b1aef720f2a8870d26d5bb (commit)
       via  58388f2e53b8428f0ecb5936d9d6c076b2003203 (commit)
       via  208dbbaf77e781a19d6efdaca32d423ea266a6f1 (commit)
       via  eb5ace77a9c1ee6ce93d827080624d566eaf572c (commit)
       via  f6f8e26e272ee0d94c36bf2be23e005bd74c55ea (commit)
       via  5b6cccfc2e34d0319e8c5358391de6fe9a5dcdf4 (commit)
       via  56a18b6b8dc444efeec0052eefc4539633e9a762 (commit)
       via  aa53f0f7d8c06ea9dd7082971d080895a56d6c14 (commit)
       via  c13d8c76021cb27bf9d5f0bf899b267ca04caa21 (commit)
       via  6a1a234386523e5be05adf0a6ac51df29bf3b7a6 (commit)
       via  25a4afa2395d6d9263b385a73cec2919c4a21830 (commit)
       via  e5f7c1b89ed635155aa022f6a14285657b152a1c (commit)
       via  e05f1d87c3764033b920fa8a227cfd05dc3ca3b8 (commit)
       via  5fe90d260706fdac0ed0678233e116213520c575 (commit)
       via  559395e392e41dd929368d820f83f58555c5e319 (commit)
       via  5f39840cf5f96ee91f826aa801d934864a55d444 (commit)
       via  0fc1237c7ba1edd9128387ba1db1bae9e7aacc27 (commit)
       via  d1d08475aec2b0f3c45fa35db5ad629ab14dfb26 (commit)
       via  45e74198ebeee9d0e2eee780185d91c20fa63513 (commit)
       via  c200bbcb68071fb2148344d629c5605498bf0656 (commit)
       via  5b1952368e65ab130340c46d5e0f3bb72a343993 (commit)
       via  c33327c47f10065f09cc32bcd93b1e7f5612e5d8 (commit)
       via  e7bd7d6ceafd9ba44c953835b6bea33d5f54b32c (commit)
       via  55eaa4303d7bc462286b4a6b7f262976f1a346bb (commit)
       via  f4663e8cab5485f19069ddb80fef073a6705c105 (commit)
       via  ca9f73e098180f9d5d188f1d1bd46031f9b81ce3 (commit)
       via  055a8352580a73069b0745d3fbddec1c488f9e59 (commit)
       via  3aeb78fd7a34c736a4ba3b985ef6a0f8432bfafa (commit)
       via  01244a662e1ad9387e27c2f5e1723c954d47a12b (commit)
       via  97e21bca2ddfc0ceb7350b741efae2c4199383ad (commit)
       via  82225f72c3af83d8ca5e2b33b0e93d32b1e2fdbf (commit)
       via  a61af89b9799857a955e5e0b7b04b1f273dd63ab (commit)
       via  6f25929f1cfee95e92142cdf8ce42fe5f2a8aae6 (commit)
       via  b4913f7bf1a1b4c11c0b614d9a7516d4ab629776 (commit)
       via  6bf4ff4eb4a3a8095bdd5d622cab24f46a0d9834 (commit)
       via  2fdacd86e25c075a059e81274a1531ed6f0b787c (commit)
       via  280d0604dbf569d0aeb3065cae12cd38876e3e5c (commit)
       via  5b3b1ee480cb8d47477972118f7ce03751699359 (commit)
       via  ee538e573d559fc8912465fa8161cd975287e807 (commit)
       via  6419f929bd1e7eb951fe1c0c0debc7e8ae30a59a (commit)
       via  d26a99607b8d1e1b861de188c321e869ebb92cd1 (commit)
       via  163a1a31471bea170a85b2e158f66c9f439bb2e4 (commit)
       via  f802f3ba317e49c1c1d16134855eb1b3c1aaeec8 (commit)
       via  1b10623a2bdc55e002defbd36eeba3f0d6f9d656 (commit)
       via  fa04b8777b196e3094f8b351c7f3d1ebf56fdd7e (commit)
       via  3ef4699944709ab91f856396c76b90f3c97df3ac (commit)
       via  950c72ccede294b7692bb7bdb20ef1bc28c3cc76 (commit)
       via  eee7c05de1c33b0d932ebbaca4370129d315e0ba (commit)
       via  5ba139c6882f7399449eafdefb2202578fbe2903 (commit)
       via  e5ad751d8372bb0306d4eb5b8311a7b9cb7c7c32 (commit)
       via  a9fd37df7cba2f48a2f4e42cc0d1f26b991b5636 (commit)
       via  fd8264e864303a947addc8f788b31ae7c7ea4c12 (commit)
       via  65253b21b0d15b2608655e90a129efbe1de24d07 (commit)
       via  5261f939f525186b89099aae541f7042e42c54ba (commit)
       via  a16ecb53a5c69269e749845e708215d5d3c75c31 (commit)
       via  c2a477d54ed891c84fb2218831d0d7950a91fdb4 (commit)
       via  56df3cb883631fc189fde26781f5d01695fcd386 (commit)
       via  6b8528fd0d34b49c44f9da2b2ce2127399fcca34 (commit)
       via  cef74673072e543a06bdc487afcad8787a811908 (commit)
       via  1b35c2aba35663034479b293e238deeff068dced (commit)
       via  8b356c0c7202c02151a882cc7676803bcaf90b75 (commit)
       via  f985b514e1b9a338b3940928415396c6a87dbce1 (commit)
       via  e1ae6846339d8ce57f61a56d1fccf00d92ef910b (commit)
       via  ceeaa8ae96db786b65715e0cb440a411fbab8b2c (commit)
       via  8d093113af5d33b4c7841ef7bc003d29c5d1268e (commit)
       via  94f1fcdbcfb0cfceaff0e850df3bdd190efb73ad (commit)
       via  8240c04e9bf91ce4d26f8f55d23216f7e48b3fd8 (commit)
       via  40fe836dcfb4fb1b37152bf9078be0351e6eea21 (commit)
       via  a4eaf309a64c5eb108653efe6796af54f4da7337 (commit)
       via  328b5fc4dbbafe7a5286d857581505a7cf55ea0e (commit)
       via  10018747ad68736c31da97ec1ad7c5eef94489a0 (commit)
       via  d0a412aeddad9a64649eb28a3a5ad1003aa97d94 (commit)
       via  9ec629f3465d8651ceaf5b766fc91598e26f7023 (commit)
       via  d06e139eb2d03ef254ab8b2f3f56083addcfe756 (commit)
       via  b169803e955bf7c5647f4c67bd851b2a9a03630c (commit)
       via  d047c08a96270d4d757dc4c0bcd4dfece3bf586a (commit)
       via  60c7cde711da05825672e5b8601ff596993a030b (commit)
       via  88871270308be3aaaeb8918c29c2b2c3ca4286e5 (commit)
       via  436f507ae4e387f7fe5e242864500a6839bfc32b (commit)
       via  054b2a99a4e527a15739c0e6a9a0247bb23a5d1a (commit)
       via  38081a3eb213dad9b2233f37e8c8f499a9e50f1a (commit)
       via  350fa8a59935fac90f02e86a28d81b4941cc7ee3 (commit)
       via  06bf41c4a9c79e450e78f3eecac362dd0b18d06c (commit)
       via  467078e47174e5a3d20caa8b1a1c8c0b35b0876f (commit)
       via  faa94e73318b57601aa9bf857387863c9be72a6b (commit)
       via  f8b99e43fcc928eccd9b30fd187d91e92782ee02 (commit)
       via  4c9e89ec998fb375031f14929775074aa1d9c903 (commit)
       via  e7ecb231083afee21757b37c4128fd222a6e93a5 (commit)
       via  a96a4dc64fe455a2f2e8a1fd2f3a66e251d6c1a3 (commit)
      from  30ab0e64b78a7e634d037c7a885546ebce010da1 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit c0672d18dc8709e15a175e781a5d690a281f6d19
Merge: 30ab0e6 28c9293
Author: JINMEI Tatuya <jinmei at isc.org>
Date:   Wed Sep 26 11:03:47 2012 -0700

    [master] Merge branch 'trac2282merge'

commit 28c929309ce6200a388e97b5cb89e81f2e061a6f
Author: JINMEI Tatuya <jinmei at isc.org>
Date:   Wed Sep 26 11:03:06 2012 -0700

    [2282merge] added virtual to a derived class dtor per convention/style guide.

commit a3a63ba5ca940d188dc28a4cd2db63d908ec3e1b
Author: JINMEI Tatuya <jinmei at isc.org>
Date:   Wed Sep 26 10:37:24 2012 -0700

    [2282merge] move an in-memory test data file to the new directory.

commit 7298821ace8f33cd683dc52856e7272e52eef589
Merge: 8660a77 7e2522e
Author: JINMEI Tatuya <jinmei at isc.org>
Date:   Wed Sep 26 10:32:21 2012 -0700

    [2282merge] Merge branch 'trac2218' into trac2282merge

commit 8660a77ac739583b013c502a903ea9cdd979ae7e
Merge: 59c096c d0a83e5
Author: JINMEI Tatuya <jinmei at isc.org>
Date:   Wed Sep 26 10:31:23 2012 -0700

    [2282merge] Merge branch 'trac2218' into trac2282merge
    
    with fixing Conflicts:
    	src/lib/datasrc/memory/zone_finder.cc
    	src/lib/datasrc/memory/zone_finder.h

-----------------------------------------------------------------------

Summary of changes:
 configure.ac                                       |    4 +-
 src/bin/auth/Makefile.am                           |    6 -
 src/bin/auth/benchmarks/Makefile.am                |    6 -
 src/bin/auth/tests/Makefile.am                     |    7 -
 src/bin/auth/tests/auth_srv_unittest.cc            |   10 +-
 src/lib/datasrc/Makefile.am                        |    3 +-
 src/lib/datasrc/client_list.cc                     |   67 ++-
 src/lib/datasrc/client_list.h                      |   58 ++-
 src/lib/datasrc/memory/Makefile.am                 |    2 +-
 src/lib/datasrc/memory/domaintree.h                |  116 ++++-
 src/lib/datasrc/memory/memory_client.cc            |   56 ++-
 src/lib/datasrc/memory/memory_client.h             |   23 +-
 src/lib/datasrc/memory/treenode_rrset.cc           |   39 +-
 src/lib/datasrc/memory/treenode_rrset.h            |    2 -
 src/lib/datasrc/memory/zone_finder.cc              |  480 +++++++++++++++++---
 src/lib/datasrc/memory/zone_finder.h               |   38 +-
 src/lib/datasrc/tests/Makefile.am                  |    2 +-
 src/lib/datasrc/tests/client_list_unittest.cc      |  151 +++---
 src/lib/datasrc/tests/faked_nsec3.cc               |   17 +
 src/lib/datasrc/tests/faked_nsec3.h                |    4 +
 .../{memory/tests => tests/memory}/.gitignore      |    0
 .../{memory/tests => tests/memory}/Makefile.am     |    3 +-
 .../tests => tests/memory}/domaintree_unittest.cc  |   62 +++
 .../memory}/memory_client_unittest.cc              |   76 ++--
 .../tests => tests/memory}/memory_segment_test.h   |    0
 .../memory}/rdata_serialization_unittest.cc        |    2 +-
 .../tests => tests/memory}/rdataset_unittest.cc    |    0
 .../tests => tests/memory}/run_unittests.cc        |    0
 .../memory}/segment_object_holder_unittest.cc      |    0
 .../tests => tests/memory}/testdata/Makefile.am    |    1 +
 .../tests => tests/memory}/testdata/empty.zone     |    0
 .../memory}/testdata/example.org-broken1.zone      |    0
 .../memory}/testdata/example.org-broken2.zone      |    0
 .../testdata/example.org-cname-and-not-nsec-1.zone |    0
 .../testdata/example.org-cname-and-not-nsec-2.zone |    0
 .../testdata/example.org-dname-ns-apex-1.zone      |    0
 .../testdata/example.org-dname-ns-apex-2.zone      |    0
 .../testdata/example.org-dname-ns-nonapex-1.zone   |    0
 .../testdata/example.org-dname-ns-nonapex-2.zone   |    0
 .../testdata/example.org-duplicate-type-bad.zone   |    0
 .../testdata/example.org-duplicate-type.zone       |    0
 .../memory}/testdata/example.org-empty.zone        |    0
 .../testdata/example.org-multiple-cname.zone       |    0
 .../testdata/example.org-multiple-dname.zone       |    0
 .../testdata/example.org-multiple-nsec3.zone       |    0
 .../testdata/example.org-multiple-nsec3param.zone  |    0
 .../memory}/testdata/example.org-multiple.zone     |    0
 .../testdata/example.org-nsec3-empty-salt.zone}    |    8 +-
 .../testdata/example.org-nsec3-fewer-labels.zone   |    0
 .../testdata/example.org-nsec3-more-labels.zone    |    0
 .../example.org-nsec3-signed-no-param.zone         |    0
 .../memory}/testdata/example.org-nsec3-signed.zone |    0
 .../memory}/testdata/example.org-out-of-zone.zone  |    0
 .../example.org-rrsig-follows-nothing.zone         |    0
 .../memory}/testdata/example.org-rrsigs.zone       |    0
 .../testdata/example.org-wildcard-dname.zone       |    0
 .../memory}/testdata/example.org-wildcard-ns.zone  |    0
 .../testdata/example.org-wildcard-nsec3.zone       |    0
 .../memory}/testdata/example.org.zone              |    0
 .../memory}/treenode_rrset_unittest.cc             |   58 ++-
 .../tests => tests/memory}/zone_data_unittest.cc   |    0
 .../tests => tests/memory}/zone_finder_unittest.cc |  349 +++++++++-----
 .../tests => tests/memory}/zone_table_unittest.cc  |    0
 src/lib/datasrc/tests/memory_datasrc_unittest.cc   |   66 ---
 src/lib/datasrc/tests/testdata/contexttest.zone    |    5 +-
 .../datasrc/tests/zone_finder_context_unittest.cc  |   39 +-
 src/lib/dns/labelsequence.cc                       |    3 +-
 src/lib/dns/nsec3hash.cc                           |   58 ++-
 src/lib/dns/nsec3hash.h                            |   34 +-
 src/lib/dns/tests/labelsequence_unittest.cc        |   33 ++
 src/lib/dns/tests/nsec3hash_unittest.cc            |   24 +-
 .../python/isc/datasrc/tests/clientlist_test.py    |   93 ++--
 72 files changed, 1420 insertions(+), 585 deletions(-)
 rename src/lib/datasrc/{memory/tests => tests/memory}/.gitignore (100%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/Makefile.am (92%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/domaintree_unittest.cc (95%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/memory_client_unittest.cc (92%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/memory_segment_test.h (100%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/rdata_serialization_unittest.cc (99%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/rdataset_unittest.cc (100%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/run_unittests.cc (100%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/segment_object_holder_unittest.cc (100%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/testdata/Makefile.am (96%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/testdata/empty.zone (100%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/testdata/example.org-broken1.zone (100%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/testdata/example.org-broken2.zone (100%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/testdata/example.org-cname-and-not-nsec-1.zone (100%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/testdata/example.org-cname-and-not-nsec-2.zone (100%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/testdata/example.org-dname-ns-apex-1.zone (100%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/testdata/example.org-dname-ns-apex-2.zone (100%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/testdata/example.org-dname-ns-nonapex-1.zone (100%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/testdata/example.org-dname-ns-nonapex-2.zone (100%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/testdata/example.org-duplicate-type-bad.zone (100%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/testdata/example.org-duplicate-type.zone (100%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/testdata/example.org-empty.zone (100%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/testdata/example.org-multiple-cname.zone (100%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/testdata/example.org-multiple-dname.zone (100%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/testdata/example.org-multiple-nsec3.zone (100%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/testdata/example.org-multiple-nsec3param.zone (100%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/testdata/example.org-multiple.zone (100%)
 copy src/lib/datasrc/tests/{testdata/example.org.nsec3-signed => memory/testdata/example.org-nsec3-empty-salt.zone} (91%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/testdata/example.org-nsec3-fewer-labels.zone (100%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/testdata/example.org-nsec3-more-labels.zone (100%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/testdata/example.org-nsec3-signed-no-param.zone (100%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/testdata/example.org-nsec3-signed.zone (100%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/testdata/example.org-out-of-zone.zone (100%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/testdata/example.org-rrsig-follows-nothing.zone (100%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/testdata/example.org-rrsigs.zone (100%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/testdata/example.org-wildcard-dname.zone (100%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/testdata/example.org-wildcard-ns.zone (100%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/testdata/example.org-wildcard-nsec3.zone (100%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/testdata/example.org.zone (100%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/treenode_rrset_unittest.cc (91%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/zone_data_unittest.cc (100%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/zone_finder_unittest.cc (84%)
 rename src/lib/datasrc/{memory/tests => tests/memory}/zone_table_unittest.cc (100%)

-----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index 31306e4..b064480 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1193,11 +1193,11 @@ AC_CONFIG_FILES([Makefile
                  src/lib/exceptions/tests/Makefile
                  src/lib/datasrc/Makefile
                  src/lib/datasrc/memory/Makefile
-                 src/lib/datasrc/memory/tests/Makefile
-                 src/lib/datasrc/memory/tests/testdata/Makefile
                  src/lib/datasrc/memory/benchmarks/Makefile
                  src/lib/datasrc/tests/Makefile
                  src/lib/datasrc/tests/testdata/Makefile
+                 src/lib/datasrc/tests/memory/Makefile
+                 src/lib/datasrc/tests/memory/testdata/Makefile
                  src/lib/xfr/Makefile
                  src/lib/xfr/tests/Makefile
                  src/lib/log/Makefile
diff --git a/src/bin/auth/Makefile.am b/src/bin/auth/Makefile.am
index 9e24433..3efa9d3 100644
--- a/src/bin/auth/Makefile.am
+++ b/src/bin/auth/Makefile.am
@@ -57,12 +57,6 @@ b10_auth_SOURCES += common.h common.cc
 b10_auth_SOURCES += statistics.cc statistics.h
 b10_auth_SOURCES += datasrc_configurator.h
 b10_auth_SOURCES += main.cc
-# This is a temporary workaround for #1206, where the InMemoryClient has been
-# moved to an ldopened library. We could add that library to LDADD, but that
-# is nonportable. This should've been moot after #1207, but there is still
-# one dependency; the in-memory-specific zone loader call is still in
-# auth.
-b10_auth_SOURCES += ${top_srcdir}/src/lib/datasrc/memory_datasrc.cc
 
 nodist_b10_auth_SOURCES = auth_messages.h auth_messages.cc
 EXTRA_DIST += auth_messages.mes
diff --git a/src/bin/auth/benchmarks/Makefile.am b/src/bin/auth/benchmarks/Makefile.am
index c09230a..948e718 100644
--- a/src/bin/auth/benchmarks/Makefile.am
+++ b/src/bin/auth/benchmarks/Makefile.am
@@ -17,12 +17,6 @@ query_bench_SOURCES += ../auth_srv.h ../auth_srv.cc
 query_bench_SOURCES += ../auth_config.h ../auth_config.cc
 query_bench_SOURCES += ../statistics.h ../statistics.cc
 query_bench_SOURCES += ../auth_log.h ../auth_log.cc
-# This is a temporary workaround for #1206, where the InMemoryClient has been
-# moved to an ldopened library. We could add that library to LDADD, but that
-# is nonportable. When #1207 is done this becomes moot anyway, and the
-# specific workaround is not needed anymore, so we can then remove this
-# line again.
-query_bench_SOURCES += ${top_srcdir}/src/lib/datasrc/memory_datasrc.cc
 
 nodist_query_bench_SOURCES = ../auth_messages.h ../auth_messages.cc
 
diff --git a/src/bin/auth/tests/Makefile.am b/src/bin/auth/tests/Makefile.am
index f87ed4c..75e4a27 100644
--- a/src/bin/auth/tests/Makefile.am
+++ b/src/bin/auth/tests/Makefile.am
@@ -52,13 +52,6 @@ run_unittests_SOURCES += query_unittest.cc
 run_unittests_SOURCES += statistics_unittest.cc
 run_unittests_SOURCES += datasrc_configurator_unittest.cc
 run_unittests_SOURCES += run_unittests.cc
-# This is a temporary workaround for #1206, where the InMemoryClient has been
-# moved to an ldopened library. We could add that library to LDADD, but that
-# is nonportable. This should've been moot after #1207, but there is still
-# one dependency; the in-memory-specific zone loader call is still in
-# auth.
-run_unittests_SOURCES += ${top_srcdir}/src/lib/datasrc/memory_datasrc.cc
-
 
 nodist_run_unittests_SOURCES = ../auth_messages.h ../auth_messages.cc
 
diff --git a/src/bin/auth/tests/auth_srv_unittest.cc b/src/bin/auth/tests/auth_srv_unittest.cc
index e86cca4..e7b4ca7 100644
--- a/src/bin/auth/tests/auth_srv_unittest.cc
+++ b/src/bin/auth/tests/auth_srv_unittest.cc
@@ -15,6 +15,7 @@
 #include <config.h>
 
 #include <util/io/sockaddr_util.h>
+#include <util/memory_segment_local.h>
 
 #include <dns/message.h>
 #include <dns/messagerenderer.h>
@@ -1393,16 +1394,19 @@ public:
              const isc::datasrc::DataSourceClientPtr
                  client(new FakeClient(info.data_src_client_ != NULL ?
                                        info.data_src_client_ :
-                                       info.cache_.get(),
+                                       info.getCacheClient(),
                                        throw_when, isc_exception, fake_rrset));
              clients_.push_back(client);
-             data_sources_.push_back(DataSourceInfo(client.get(),
-                 isc::datasrc::DataSourceClientContainerPtr(), false));
+             data_sources_.push_back(
+                 DataSourceInfo(client.get(),
+                                isc::datasrc::DataSourceClientContainerPtr(),
+                                false, RRClass::IN(), mem_sgmt_));
         }
     }
 private:
     const boost::shared_ptr<isc::datasrc::ConfigurableClientList> real_;
     vector<isc::datasrc::DataSourceClientPtr> clients_;
+    MemorySegmentLocal mem_sgmt_;
 };
 
 } // end anonymous namespace for throwing proxy classes
diff --git a/src/lib/datasrc/Makefile.am b/src/lib/datasrc/Makefile.am
index b889d4c..862de8a 100644
--- a/src/lib/datasrc/Makefile.am
+++ b/src/lib/datasrc/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = . memory tests
+SUBDIRS = memory . tests
 
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
@@ -60,6 +60,7 @@ libb10_datasrc_la_LIBADD = $(top_builddir)/src/lib/exceptions/libb10-exceptions.
 libb10_datasrc_la_LIBADD += $(top_builddir)/src/lib/dns/libb10-dns++.la
 libb10_datasrc_la_LIBADD += $(top_builddir)/src/lib/log/libb10-log.la
 libb10_datasrc_la_LIBADD += $(top_builddir)/src/lib/cc/libb10-cc.la
+libb10_datasrc_la_LIBADD += $(builddir)/memory/libdatasrc_memory.la
 libb10_datasrc_la_LIBADD += $(SQLITE_LIBS)
 
 BUILT_SOURCES = datasrc_config.h datasrc_messages.h datasrc_messages.cc
diff --git a/src/lib/datasrc/client_list.cc b/src/lib/datasrc/client_list.cc
index 3c0ea19..865a1ce 100644
--- a/src/lib/datasrc/client_list.cc
+++ b/src/lib/datasrc/client_list.cc
@@ -12,10 +12,12 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <util/memory_segment_local.h>
+
 #include "client_list.h"
 #include "client.h"
 #include "factory.h"
-#include "memory_datasrc.h"
+#include "memory/memory_client.h"
 #include "logger.h"
 #include <dns/masterload.h>
 
@@ -25,32 +27,58 @@
 using namespace isc::data;
 using namespace isc::dns;
 using namespace std;
+using isc::util::MemorySegment;
 using boost::lexical_cast;
 using boost::shared_ptr;
 using boost::dynamic_pointer_cast;
+using isc::datasrc::memory::InMemoryClient;
 
 namespace isc {
 namespace datasrc {
 
 ConfigurableClientList::DataSourceInfo::DataSourceInfo(
     DataSourceClient* data_src_client,
-    const DataSourceClientContainerPtr& container, bool has_cache) :
+    const DataSourceClientContainerPtr& container, bool has_cache,
+    const RRClass& rrclass, MemorySegment& mem_sgmt) :
     data_src_client_(data_src_client),
     container_(container)
 {
     if (has_cache) {
-        cache_.reset(new InMemoryClient);
+        cache_.reset(new InMemoryClient(mem_sgmt, rrclass));
     }
 }
 
-ConfigurableClientList::DataSourceInfo::DataSourceInfo(bool has_cache) :
+ConfigurableClientList::DataSourceInfo::DataSourceInfo(
+    const RRClass& rrclass, MemorySegment& mem_sgmt, bool has_cache) :
     data_src_client_(NULL)
 {
     if (has_cache) {
-        cache_.reset(new InMemoryClient);
+        cache_.reset(new InMemoryClient(mem_sgmt, rrclass));
     }
 }
 
+const DataSourceClient*
+ConfigurableClientList::DataSourceInfo::getCacheClient() const {
+    return (cache_.get());
+}
+
+ConfigurableClientList::ConfigurableClientList(const RRClass& rrclass) :
+    rrclass_(rrclass),
+    mem_sgmt_(new util::MemorySegmentLocal),
+    configuration_(new isc::data::ListElement),
+    allow_cache_(false)
+{}
+
+ConfigurableClientList::~ConfigurableClientList() {
+    // Explicitly clear the contained data source clients, and check memory
+    // leak.  assert() (with abort on failure) may be too harsh, but
+    // it's probably better to find more leaks initially.  Once it's stabilized
+    // we should probably revisit it.
+
+    data_sources_.clear();
+    assert(mem_sgmt_->allMemoryDeallocated());
+}
+
 void
 ConfigurableClientList::configure(const ConstElementPtr& config,
                                   bool allow_cache)
@@ -98,14 +126,16 @@ ConfigurableClientList::configure(const ConstElementPtr& config,
                     isc_throw(ConfigurationError, "The cache must be enabled "
                               "for the MasterFiles type");
                 }
-                new_data_sources.push_back(DataSourceInfo(true));
+                new_data_sources.push_back(DataSourceInfo(rrclass_, *mem_sgmt_,
+                                                          true));
             } else {
                 // Ask the factory to create the data source for us
                 const DataSourcePair ds(this->getDataSourceClient(type,
                                                                   paramConf));
                 // And put it into the vector
                 new_data_sources.push_back(DataSourceInfo(ds.first, ds.second,
-                                                          want_cache));
+                                                          want_cache, rrclass_,
+                                                          *mem_sgmt_));
             }
 
             if (want_cache) {
@@ -141,13 +171,10 @@ ConfigurableClientList::configure(const ConstElementPtr& config,
                 for (vector<string>::const_iterator it(zones_origins.begin());
                      it != zones_origins.end(); ++it) {
                     const Name origin(*it);
-                    shared_ptr<InMemoryZoneFinder>
-                        finder(new
-                            InMemoryZoneFinder(rrclass_, origin));
                     if (type == "MasterFiles") {
                         try {
-                            finder->load(paramConf->get(*it)->stringValue());
-                            cache->addZone(finder);
+                            cache->load(origin,
+                                        paramConf->get(*it)->stringValue());
                         } catch (const isc::dns::MasterLoadError& mle) {
                             LOG_ERROR(logger, DATASRC_MASTERLOAD_ERROR)
                                 .arg(mle.what());
@@ -165,8 +192,7 @@ ConfigurableClientList::configure(const ConstElementPtr& config,
                             isc_throw(isc::Unexpected, "Got NULL iterator "
                                       "for zone " << origin);
                         }
-                        finder->load(*iterator);
-                        cache->addZone(finder);
+                        cache->load(origin, *iterator);
                     }
                 }
             }
@@ -324,14 +350,11 @@ ConfigurableClientList::reload(const Name& name) {
     }
     // Try to convert the finder to in-memory one. If it is the cache,
     // it should work.
-    shared_ptr<InMemoryZoneFinder>
-        finder(dynamic_pointer_cast<InMemoryZoneFinder>(result.finder));
-    const DataSourceInfo* info(result.info);
     // It is of a different type or there's no cache.
-    if (!info->cache_ || !finder) {
+    if (!result.info->cache_) {
         return (ZONE_NOT_CACHED);
     }
-    DataSourceClient* client(info->data_src_client_);
+    DataSourceClient* client(result.info->data_src_client_);
     if (client) {
         // Now do the final reload. If it does not exist in client,
         // DataSourceError is thrown, which is exactly the result what we
@@ -340,15 +363,15 @@ ConfigurableClientList::reload(const Name& name) {
         if (!iterator) {
             isc_throw(isc::Unexpected, "Null iterator from " << name);
         }
-        finder->load(*iterator);
+        result.info->cache_->load(name, *iterator);
     } else {
         // The MasterFiles special case
-        const string filename(finder->getFileName());
+        const string filename(result.info->cache_->getFileName(name));
         if (filename.empty()) {
             isc_throw(isc::Unexpected, "Confused about missing both filename "
                       "and data source");
         }
-        finder->load(filename);
+        result.info->cache_->load(name, filename);
     }
     return (ZONE_RELOADED);
 }
diff --git a/src/lib/datasrc/client_list.h b/src/lib/datasrc/client_list.h
index 0dd522f..61544ef 100644
--- a/src/lib/datasrc/client_list.h
+++ b/src/lib/datasrc/client_list.h
@@ -15,6 +15,8 @@
 #ifndef DATASRC_CONTAINER_H
 #define DATASRC_CONTAINER_H
 
+#include <util/memory_segment.h>
+
 #include <dns/name.h>
 #include <dns/rrclass.h>
 #include <cc/data.h>
@@ -22,6 +24,7 @@
 
 #include <vector>
 #include <boost/shared_ptr.hpp>
+#include <boost/scoped_ptr.hpp>
 #include <boost/noncopyable.hpp>
 
 namespace isc {
@@ -34,7 +37,13 @@ typedef boost::shared_ptr<DataSourceClient> DataSourceClientPtr;
 class DataSourceClientContainer;
 typedef boost::shared_ptr<DataSourceClientContainer>
     DataSourceClientContainerPtr;
+
+// XXX: it's better to even hide the existence of the "memory" namespace.
+// We should probably consider pimpl for details of ConfigurableClientList
+// and hide real definitions except for itself and tests.
+namespace memory {
 class InMemoryClient;
+}
 
 /// \brief The list of data source clients.
 ///
@@ -209,11 +218,11 @@ public:
     /// \brief Constructor
     ///
     /// \param rrclass For which class the list should work.
-    ConfigurableClientList(const isc::dns::RRClass &rrclass) :
-        rrclass_(rrclass),
-        configuration_(new isc::data::ListElement),
-        allow_cache_(false)
-    {}
+    ConfigurableClientList(const isc::dns::RRClass& rrclass);
+
+    /// \brief Destructor
+    virtual ~ConfigurableClientList();
+
     /// \brief Exception thrown when there's an error in configuration.
     class ConfigurationError : public Exception {
     public:
@@ -290,24 +299,27 @@ public:
     /// \todo The content yet to be defined.
     struct DataSourceInfo {
         // Plays a role of default constructor too (for vector)
-        DataSourceInfo(bool has_cache = false);
+        DataSourceInfo(const dns::RRClass& rrclass,
+                       util::MemorySegment& mem_sgmt,
+                       bool has_cache = false);
         DataSourceInfo(DataSourceClient* data_src_client,
                        const DataSourceClientContainerPtr& container,
-                       bool has_cache);
+                       bool has_cache, const dns::RRClass& rrclass,
+                       util::MemorySegment& mem_sgmt);
         DataSourceClient* data_src_client_;
         DataSourceClientContainerPtr container_;
-        boost::shared_ptr<InMemoryClient> cache_;
+
+        // Accessor to cache_ in the form of DataSourceClient, hiding
+        // the existence of InMemoryClient as much as possible.  We should
+        // really consider cleaner abstraction, but for now it works.
+        // This is also only intended to be used in auth unit tests right now.
+        // No other applications or tests may use it.
+        const DataSourceClient* getCacheClient() const;
+        boost::shared_ptr<memory::InMemoryClient> cache_;
     };
 
     /// \brief The collection of data sources.
     typedef std::vector<DataSourceInfo> DataSources;
-protected:
-    /// \brief The data sources held here.
-    ///
-    /// All our data sources are stored here. It is protected to let the
-    /// tests in. You should consider it private if you ever want to
-    /// derive this class (which is not really recommended anyway).
-    DataSources data_sources_;
 
     /// \brief Convenience type alias.
     ///
@@ -357,10 +369,26 @@ private:
     void findInternal(MutableResult& result, const dns::Name& name,
                       bool want_exact_match, bool want_finder) const;
     const isc::dns::RRClass rrclass_;
+
+    /// \brief Memory segment for in-memory cache.
+    ///
+    /// Note that this must be placed before data_sources_ so it won't be
+    /// destroyed before the built objects in the destructor.
+    boost::scoped_ptr<util::MemorySegment> mem_sgmt_;
+
     /// \brief Currently active configuration.
     isc::data::ConstElementPtr configuration_;
+
     /// \brief The last set value of allow_cache.
     bool allow_cache_;
+
+protected:
+    /// \brief The data sources held here.
+    ///
+    /// All our data sources are stored here. It is protected to let the
+    /// tests in. You should consider it private if you ever want to
+    /// derive this class (which is not really recommended anyway).
+    DataSources data_sources_;
 };
 
 } // namespace datasrc
diff --git a/src/lib/datasrc/memory/Makefile.am b/src/lib/datasrc/memory/Makefile.am
index eea9c0b..3bdec0d 100644
--- a/src/lib/datasrc/memory/Makefile.am
+++ b/src/lib/datasrc/memory/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = . tests benchmarks
+SUBDIRS = . benchmarks
 
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
diff --git a/src/lib/datasrc/memory/domaintree.h b/src/lib/datasrc/memory/domaintree.h
index b29f10f..2ab32c1 100644
--- a/src/lib/datasrc/memory/domaintree.h
+++ b/src/lib/datasrc/memory/domaintree.h
@@ -373,10 +373,23 @@ private:
         }
     }
 
+    /// \brief returns if the node is a subtree's root node
+    ///
+    /// This method takes a node and returns \c true if it is the root
+    /// node of the subtree it belongs to.
+    ///
+    /// This method never throws an exception.
     bool isSubTreeRoot() const {
         return ((flags_ & FLAG_SUBTREE_ROOT) != 0);
     }
 
+    /// \brief returns the root of its subtree
+    ///
+    /// This method takes a node and returns the root of its subtree.
+    ///
+    /// This method never throws an exception.
+    const DomainTreeNode<T>* getSubTreeRoot() const;
+
 public:
     /// \brief returns the parent of the root of its subtree
     ///
@@ -388,7 +401,6 @@ public:
     /// This method never throws an exception.
     const DomainTreeNode<T>* getUpperNode() const;
 
-private:
     /// \brief return the next node which is bigger than current node
     /// in the same subtree
     ///
@@ -423,6 +435,7 @@ private:
     /// This method never throws an exception.
     const DomainTreeNode<T>* predecessor() const;
 
+private:
     /// \brief private shared implementation of successor and predecessor
     ///
     /// As the two mentioned functions are merely mirror images of each other,
@@ -538,7 +551,7 @@ DomainTreeNode<T>::~DomainTreeNode() {
 
 template <typename T>
 const DomainTreeNode<T>*
-DomainTreeNode<T>::getUpperNode() const {
+DomainTreeNode<T>::getSubTreeRoot() const {
     const DomainTreeNode<T>* current = this;
 
     // current would never be equal to NULL here (in a correct tree
@@ -547,7 +560,13 @@ DomainTreeNode<T>::getUpperNode() const {
         current = current->getParent();
     }
 
-    return (current->getParent());
+    return (current);
+}
+
+template <typename T>
+const DomainTreeNode<T>*
+DomainTreeNode<T>::getUpperNode() const {
+    return (getSubTreeRoot()->getParent());
 }
 
 template <typename T>
@@ -555,7 +574,17 @@ isc::dns::LabelSequence
 DomainTreeNode<T>::getAbsoluteLabels(
     uint8_t buf[isc::dns::LabelSequence::MAX_SERIALIZED_LENGTH]) const
 {
-    isc::dns::LabelSequence result(getLabels(), buf);
+    // If the current node already has absolute labels, just return it.
+    // This should normally be the case for the origin node if this tree
+    // is used to represent a single DNS zone.
+    const isc::dns::LabelSequence cur_labels(getLabels());
+    if (cur_labels.isAbsolute()) {
+        return (cur_labels);
+    }
+
+    // Otherwise, build the absolute sequence traversing the tree of tree
+    // toward the top root.
+    isc::dns::LabelSequence result(cur_labels, buf);
     const DomainTreeNode<T>* upper = getUpperNode();
     while (upper != NULL) {
         result.extend(upper->getLabels(), buf);
@@ -672,14 +701,26 @@ public:
     /// The default constructor.
     ///
     /// \exception None
-    DomainTreeNodeChain() : node_count_(0), last_compared_(NULL),
+    DomainTreeNodeChain() : level_count_(0), last_compared_(NULL),
                         // XXX: meaningless initial values:
                         last_comparison_(0, 0,
                                          isc::dns::NameComparisonResult::EQUAL)
     {}
 
+    /// \brief Copy constructor.
+    ///
+    /// \exception None
+    DomainTreeNodeChain(const DomainTreeNodeChain<T>& other) :
+        level_count_(other.level_count_),
+        last_compared_(other.last_compared_),
+        last_comparison_(other.last_comparison_)
+    {
+        for (size_t i = 0; i < level_count_; i++) {
+            nodes_[i] = other.nodes_[i];
+        }
+    }
+
 private:
-    DomainTreeNodeChain(const DomainTreeNodeChain<T>&);
     DomainTreeNodeChain<T>& operator=(const DomainTreeNodeChain<T>&);
     //@}
 
@@ -691,7 +732,7 @@ public:
     ///
     /// \exception None
     void clear() {
-        node_count_ = 0;
+        level_count_ = 0;
         last_compared_ = NULL;
     }
 
@@ -732,7 +773,7 @@ public:
     /// chain, 0 will be returned.
     ///
     /// \exception None
-    unsigned int getLevelCount() const { return (node_count_); }
+    size_t getLevelCount() const { return (level_count_); }
 
     /// \brief return the absolute name for the node which this
     /// \c DomainTreeNodeChain currently refers to.
@@ -750,11 +791,11 @@ public:
 
         const DomainTreeNode<T>* top_node = top();
         isc::dns::Name absolute_name = top_node->getName();
-        int node_count = node_count_ - 1;
-        while (node_count > 0) {
-            top_node = nodes_[node_count - 1];
+        size_t level = level_count_ - 1;
+        while (level > 0) {
+            top_node = nodes_[level - 1];
             absolute_name = absolute_name.concatenate(top_node->getName());
-            --node_count;
+            --level;
         }
         return (absolute_name);
     }
@@ -768,7 +809,7 @@ private:
     /// \brief return whether node chain has node in it.
     ///
     /// \exception None
-    bool isEmpty() const { return (node_count_ == 0); }
+    bool isEmpty() const { return (level_count_ == 0); }
 
     /// \brief return the top node for the node chain
     ///
@@ -778,7 +819,7 @@ private:
     /// \exception None
     const DomainTreeNode<T>* top() const {
         assert(!isEmpty());
-        return (nodes_[node_count_ - 1]);
+        return (nodes_[level_count_ - 1]);
     }
 
     /// \brief pop the top node from the node chain
@@ -789,7 +830,7 @@ private:
     /// \exception None
     void pop() {
         assert(!isEmpty());
-        --node_count_;
+        --level_count_;
     }
 
     /// \brief add the node into the node chain
@@ -800,8 +841,8 @@ private:
     ///
     /// \exception None
     void push(const DomainTreeNode<T>* node) {
-        assert(node_count_ < RBT_MAX_LEVEL);
-        nodes_[node_count_++] = node;
+        assert(level_count_ < RBT_MAX_LEVEL);
+        nodes_[level_count_++] = node;
     }
 
 private:
@@ -810,7 +851,7 @@ private:
     // it's also equal to the possible maximum level.
     const static int RBT_MAX_LEVEL = isc::dns::Name::MAX_LABELS;
 
-    int node_count_;
+    size_t level_count_;
     const DomainTreeNode<T>* nodes_[RBT_MAX_LEVEL];
     const DomainTreeNode<T>* last_compared_;
     isc::dns::NameComparisonResult last_comparison_;
@@ -1265,12 +1306,20 @@ public:
     const DomainTreeNode<T>*
     previousNode(DomainTreeNodeChain<T>& node_path) const;
 
+    /// \brief return the largest node in the tree of trees.
+    ///
+    /// \throw none
+    ///
+    /// \return A \c DomainTreeNode that is the largest node in the
+    /// tree. If there are no nodes, then \c NULL is returned.
+    const DomainTreeNode<T>* largestNode() const;
+
     /// \brief Get the total number of nodes in the tree
     ///
     /// It includes nodes internally created as a result of adding a domain
     /// name that is a subdomain of an existing node of the tree.
     /// This function is mainly intended to be used for debugging.
-    int getNodeCount() const { return (node_count_); }
+    uint32_t getNodeCount() const { return (node_count_); }
 
     /// \name Debug function
     //@{
@@ -1402,8 +1451,15 @@ private:
     //@}
 
     typename DomainTreeNode<T>::DomainTreeNodePtr root_;
-    /// the node count of current tree
-    unsigned int node_count_;
+
+    /// the node count of current tree.
+    ///
+    /// Note: uint32_t may look awkward, but we intentionally choose it so
+    /// that needsReturnEmptyNode_ below won't make cause extra padding
+    /// in 64-bit machines (and we can minimize the total size of this class).
+    /// 2^32 - 1 should be a reasonable max of possible number of nodes.
+    uint32_t node_count_;
+
     /// search policy for domaintree
     const bool needsReturnEmptyNode_;
 };
@@ -1710,6 +1766,24 @@ DomainTree<T>::previousNode(DomainTreeNodeChain<T>& node_path) const {
 }
 
 template <typename T>
+const DomainTreeNode<T>*
+DomainTree<T>::largestNode() const {
+    const DomainTreeNode<T>* node = root_.get();
+    while (node != NULL) {
+        // We go right first, then down.
+        if (node->getRight() != NULL) {
+            node = node->getRight();
+        } else if (node->getDown() != NULL) {
+            node = node->getDown();
+        } else {
+            break;
+        }
+    }
+
+    return (node);
+}
+
+template <typename T>
 typename DomainTree<T>::Result
 DomainTree<T>::insert(util::MemorySegment& mem_sgmt,
                       const isc::dns::Name& target_name,
diff --git a/src/lib/datasrc/memory/memory_client.cc b/src/lib/datasrc/memory/memory_client.cc
index 66822d2..a51a1a0 100644
--- a/src/lib/datasrc/memory/memory_client.cc
+++ b/src/lib/datasrc/memory/memory_client.cc
@@ -22,6 +22,7 @@
 #include <datasrc/memory/domaintree.h>
 #include <datasrc/memory/segment_object_holder.h>
 #include <datasrc/memory/treenode_rrset.h>
+#include <datasrc/memory/zone_finder.h>
 
 #include <util/memory_segment_local.h>
 
@@ -100,9 +101,6 @@ public:
         FileNameTree::destroy(mem_sgmt_, file_name_tree_, deleter);
 
         ZoneTable::destroy(mem_sgmt_, zone_table_, rrclass_);
-
-        // see above for the assert().
-        assert(mem_sgmt_.allMemoryDeallocated());
     }
 
     util::MemorySegment& mem_sgmt_;
@@ -326,6 +324,7 @@ public:
         if (nsec3_data == NULL) {
             nsec3_data = NSEC3Data::create(mem_sgmt_, nsec3_rdata);
             zone_data.setNSEC3Data(nsec3_data);
+            zone_data.setSigned(true);
         } else {
             size_t salt_len = nsec3_data->getSaltLen();
             const uint8_t* salt_data = nsec3_data->getSaltData();
@@ -333,7 +332,12 @@ public:
 
             if ((nsec3_rdata.getHashalg() != nsec3_data->hashalg) ||
                 (nsec3_rdata.getIterations() != nsec3_data->iterations) ||
-                (salt_data_2.size() != salt_len) ||
+                (salt_data_2.size() != salt_len)) {
+                isc_throw(AddError,
+                          "NSEC3 with inconsistent parameters: " <<
+                          rrset->toText());
+            }
+            if ((salt_len > 0) &&
                 (std::memcmp(&salt_data_2[0], salt_data, salt_len) != 0)) {
                 isc_throw(AddError,
                           "NSEC3 with inconsistent parameters: " <<
@@ -341,17 +345,10 @@ public:
             }
         }
 
-        string fst_label = rrset->getName().split(0, 1).toText(true);
-        transform(fst_label.begin(), fst_label.end(), fst_label.begin(),
-                  ::toupper);
-
         ZoneNode* node;
-        nsec3_data->insertName(mem_sgmt_, Name(fst_label), &node);
+        nsec3_data->insertName(mem_sgmt_, rrset->getName(), &node);
 
         RdataEncoder encoder;
-
-        // We assume that rrsig has already been checked to match rrset
-        // by the caller.
         RdataSet* set = RdataSet::create(mem_sgmt_, encoder, rrset, rrsig);
         RdataSet* old_set = node->setData(set);
         if (old_set != NULL) {
@@ -416,6 +413,7 @@ public:
                 if (nsec3_data == NULL) {
                     nsec3_data = NSEC3Data::create(mem_sgmt_, param);
                     zone_data.setNSEC3Data(nsec3_data);
+                    zone_data.setSigned(true);
                 } else {
                     size_t salt_len = nsec3_data->getSaltLen();
                     const uint8_t* salt_data = nsec3_data->getSaltData();
@@ -423,7 +421,13 @@ public:
 
                     if ((param.getHashalg() != nsec3_data->hashalg) ||
                         (param.getIterations() != nsec3_data->iterations) ||
-                        (salt_data_2.size() != salt_len) ||
+                        (salt_data_2.size() != salt_len)) {
+                        isc_throw(AddError,
+                                  "NSEC3PARAM with inconsistent parameters: "
+                                  << rrset->toText());
+                    }
+
+                    if ((salt_len > 0) &&
                         (std::memcmp(&salt_data_2[0],
                                      salt_data, salt_len) != 0)) {
                         isc_throw(AddError,
@@ -606,7 +610,7 @@ InMemoryClient::InMemoryClientImpl::load(
     }
 
     LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEMORY_MEM_ADD_ZONE).
-        arg(zone_name).arg(rrclass_.toText());
+        arg(zone_name).arg(rrclass_);
 
     // Set the filename in file_name_tree_ now, so that getFileName()
     // can use it (during zone reloading).
@@ -686,21 +690,25 @@ InMemoryClient::getZoneCount() const {
     return (impl_->zone_count_);
 }
 
-isc::datasrc::memory::ZoneTable::FindResult
-InMemoryClient::findZone2(const isc::dns::Name& zone_name) const {
+isc::datasrc::DataSourceClient::FindResult
+InMemoryClient::findZone(const isc::dns::Name& zone_name) const {
     LOG_DEBUG(logger, DBG_TRACE_DATA,
               DATASRC_MEMORY_MEM_FIND_ZONE).arg(zone_name);
+
     ZoneTable::FindResult result(impl_->zone_table_->findZone(zone_name));
-    return (result);
+
+    ZoneFinderPtr finder;
+    if (result.code != result::NOTFOUND) {
+        finder.reset(new InMemoryZoneFinder(*result.zone_data, getClass()));
+    }
+
+    return (DataSourceClient::FindResult(result.code, finder));
 }
 
-isc::datasrc::DataSourceClient::FindResult
-InMemoryClient::findZone(const isc::dns::Name&) const {
-    // This variant of findZone() is not implemented and should be
-    // removed eventually. It currently throws an exception. It is
-    // required right now to derive from DataSourceClient.
-    isc_throw(isc::NotImplemented,
-              "This variant of findZone() is not implemented.");
+const ZoneData*
+InMemoryClient::findZoneData(const isc::dns::Name& zone_name) {
+    ZoneTable::FindResult result(impl_->zone_table_->findZone(zone_name));
+    return (result.zone_data);
 }
 
 result::Result
diff --git a/src/lib/datasrc/memory/memory_client.h b/src/lib/datasrc/memory/memory_client.h
index 4c3ad27..330d62e 100644
--- a/src/lib/datasrc/memory/memory_client.h
+++ b/src/lib/datasrc/memory/memory_client.h
@@ -20,11 +20,7 @@
 #include <datasrc/iterator.h>
 #include <datasrc/client.h>
 #include <datasrc/memory/zone_table.h>
-
-// for isc::datasrc::ZoneTable::FindResult returned by findZone(). This
-// variant of findZone() is not implemented and should be removed
-// eventually.
-#include <datasrc/zonetable.h>
+#include <datasrc/memory/zone_data.h>
 
 #include <string>
 
@@ -206,19 +202,22 @@ public:
         { }
     };
 
-    /// Returns a \c ZoneTable result that best matches the given name.
+    /// Returns a \c ZoneFinder result that best matches the given name.
     ///
     /// This derived version of the method never throws an exception.
     /// For other details see \c DataSourceClient::findZone().
-    virtual isc::datasrc::memory::ZoneTable::FindResult
-    findZone2(const isc::dns::Name& name) const;
-
-    // This variant of findZone() is not implemented and should be
-    // removed eventually. It currently throws an exception. It is
-    // required right now to derive from DataSourceClient.
     virtual isc::datasrc::DataSourceClient::FindResult
     findZone(const isc::dns::Name& name) const;
 
+    /// Returns a \c ZoneData in the result that best matches the given
+    /// name.
+    ///
+    /// This is mainly intended for use in unit tests and should not be
+    /// used in other code.
+    ///
+    /// \throws none
+    const ZoneData* findZoneData(const isc::dns::Name& name);
+
     /// \brief Implementation of the getIterator method
     virtual isc::datasrc::ZoneIteratorPtr
     getIterator(const isc::dns::Name& name, bool separate_rrs = false) const;
diff --git a/src/lib/datasrc/memory/tests/.gitignore b/src/lib/datasrc/memory/tests/.gitignore
deleted file mode 100644
index d6d1ec8..0000000
--- a/src/lib/datasrc/memory/tests/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/run_unittests
diff --git a/src/lib/datasrc/memory/tests/Makefile.am b/src/lib/datasrc/memory/tests/Makefile.am
deleted file mode 100644
index 74b1a3d..0000000
--- a/src/lib/datasrc/memory/tests/Makefile.am
+++ /dev/null
@@ -1,50 +0,0 @@
-SUBDIRS = testdata .
-
-AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
-AM_CPPFLAGS += -I$(top_builddir)/src/lib/dns -I$(top_srcdir)/src/lib/dns
-AM_CPPFLAGS += $(BOOST_INCLUDES)
-AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(abs_srcdir)/testdata\"
-
-AM_CXXFLAGS = $(B10_CXXFLAGS)
-
-if USE_STATIC_LINK
-AM_LDFLAGS = -static
-endif
-
-CLEANFILES = *.gcno *.gcda
-
-TESTS_ENVIRONMENT = \
-	$(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
-
-TESTS =
-if HAVE_GTEST
-TESTS += run_unittests
-
-run_unittests_SOURCES = run_unittests.cc
-run_unittests_SOURCES += rdata_serialization_unittest.cc
-run_unittests_SOURCES += rdataset_unittest.cc
-run_unittests_SOURCES += domaintree_unittest.cc
-run_unittests_SOURCES += treenode_rrset_unittest.cc
-run_unittests_SOURCES += zone_table_unittest.cc
-run_unittests_SOURCES += zone_data_unittest.cc
-run_unittests_SOURCES += zone_finder_unittest.cc
-run_unittests_SOURCES += ../../tests/faked_nsec3.h ../../tests/faked_nsec3.cc
-run_unittests_SOURCES += memory_segment_test.h
-run_unittests_SOURCES += segment_object_holder_unittest.cc
-run_unittests_SOURCES += memory_client_unittest.cc
-
-run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
-run_unittests_LDFLAGS  = $(AM_LDFLAGS)  $(GTEST_LDFLAGS)
-
-run_unittests_LDADD = $(builddir)/../libdatasrc_memory.la
-run_unittests_LDADD += $(top_builddir)/src/lib/datasrc/libb10-datasrc.la
-run_unittests_LDADD += $(top_builddir)/src/lib/dns/libb10-dns++.la
-run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
-run_unittests_LDADD += $(top_builddir)/src/lib/util/libb10-util.la
-run_unittests_LDADD += $(top_builddir)/src/lib/testutils/libb10-testutils.la
-run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
-run_unittests_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
-run_unittests_LDADD += $(GTEST_LDADD)
-endif
-
-noinst_PROGRAMS = $(TESTS)
diff --git a/src/lib/datasrc/memory/tests/domaintree_unittest.cc b/src/lib/datasrc/memory/tests/domaintree_unittest.cc
deleted file mode 100644
index ef90050..0000000
--- a/src/lib/datasrc/memory/tests/domaintree_unittest.cc
+++ /dev/null
@@ -1,1230 +0,0 @@
-// Copyright (C) 2010  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 <gtest/gtest.h>
-
-#include <exceptions/exceptions.h>
-
-#include <util/memory_segment_local.h>
-
-#include <dns/name.h>
-#include <dns/rrclass.h>
-#include <dns/rrset.h>
-#include <dns/rrtype.h>
-#include <dns/rrttl.h>
-
-#include <datasrc/memory/domaintree.h>
-
-#include <dns/tests/unittest_util.h>
-
-using namespace std;
-using namespace isc;
-using namespace isc::dns;
-using isc::UnitTestUtil;
-using namespace isc::datasrc::memory;
-
-// XXX: some compilers cannot find class static constants used in
-// EXPECT_xxx macros, for which we need an explicit empty definition.
-const size_t Name::MAX_LABELS;
-
-/* The initial structure of dtree
- *
- *             .
- *             |
- *             b
- *           /   \
- *          a    d.e.f
- *              /  |   \
- *             c   |    g.h
- *                 |     |
- *                w.y    i
- *              /  |  \   \
- *             x   |   z   k
- *                 |   |
- *                 p   j
- *               /   \
- *              o     q
- */
-
-namespace {
-
-void deleteData(int* i) {
-    delete i;
-}
-
-typedef DomainTree<int> TestDomainTree;
-typedef DomainTreeNode<int> TestDomainTreeNode;
-typedef DomainTreeNodeChain<int> TestDomainTreeNodeChain;
-
-class TreeHolder {
-public:
-    TreeHolder(util::MemorySegment& mem_sgmt, TestDomainTree* tree) :
-        mem_sgmt_(mem_sgmt), tree_(tree)
-    {}
-    ~TreeHolder() {
-        TestDomainTree::destroy(mem_sgmt_, tree_, deleteData);
-    }
-    TestDomainTree* get() { return (tree_); }
-private:
-    util::MemorySegment& mem_sgmt_;
-    TestDomainTree* tree_;
-};
-
-class DomainTreeTest : public::testing::Test {
-protected:
-    DomainTreeTest() :
-        dtree_holder_(mem_sgmt_, TestDomainTree::create(mem_sgmt_)),
-        dtree_expose_empty_node_holder_(mem_sgmt_,
-                                         TestDomainTree::create(mem_sgmt_, true)),
-        dtree(*dtree_holder_.get()),
-        dtree_expose_empty_node(*dtree_expose_empty_node_holder_.get()),
-        cdtnode(NULL)
-    {
-        const char* const domain_names[] = {
-            "c", "b", "a", "x.d.e.f", "z.d.e.f", "g.h", "i.g.h", "o.w.y.d.e.f",
-            "j.z.d.e.f", "p.w.y.d.e.f", "q.w.y.d.e.f", "k.g.h"};
-        int name_count = sizeof(domain_names) / sizeof(domain_names[0]);
-        for (int i = 0; i < name_count; ++i) {
-            dtree.insert(mem_sgmt_, Name(domain_names[i]), &dtnode);
-            // Check the node doesn't have any data initially.
-            EXPECT_EQ(static_cast<int*>(NULL),
-                      dtnode->setData(new int(i + 1)));
-
-            dtree_expose_empty_node.insert(mem_sgmt_, Name(domain_names[i]),
-                                            &dtnode);
-            EXPECT_EQ(static_cast<int*>(NULL), dtnode->setData(new int(i + 1)));
-        }
-    }
-
-    util::MemorySegmentLocal mem_sgmt_;
-    TreeHolder dtree_holder_;
-    TreeHolder dtree_expose_empty_node_holder_;
-    TestDomainTree& dtree;
-    TestDomainTree& dtree_expose_empty_node;
-    TestDomainTreeNode* dtnode;
-    const TestDomainTreeNode* cdtnode;
-    uint8_t buf[LabelSequence::MAX_SERIALIZED_LENGTH];
-};
-
-TEST_F(DomainTreeTest, nodeCount) {
-    EXPECT_EQ(15, dtree.getNodeCount());
-
-    // Delete all nodes, then the count should be set to 0.  This also tests
-    // the behavior of deleteAllNodes().
-    dtree.deleteAllNodes(mem_sgmt_, deleteData);
-    EXPECT_EQ(0, dtree.getNodeCount());
-}
-
-TEST_F(DomainTreeTest, setGetData) {
-    // set new data to an existing node.  It should have some data.
-    int* newdata = new int(11);
-    int* olddata = dtnode->setData(newdata);
-    EXPECT_NE(static_cast<int*>(NULL), olddata);
-    deleteData(olddata);
-    EXPECT_EQ(11, *(dtnode->getData()));
-
-    // clear the node.  we should get the new data back we just passed.
-    olddata = dtnode->setData(NULL);
-    EXPECT_EQ(newdata, olddata);
-    deleteData(olddata);
-}
-
-TEST_F(DomainTreeTest, insertNames) {
-    EXPECT_EQ(TestDomainTree::ALREADYEXISTS, dtree.insert(mem_sgmt_,
-                                                        Name("d.e.f"),
-                                                        &dtnode));
-    EXPECT_EQ(Name("d.e.f"), dtnode->getName());
-    EXPECT_EQ(15, dtree.getNodeCount());
-
-    // insert not exist node
-    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_, Name("0"),
-                                                  &dtnode));
-    EXPECT_EQ(Name("0"), dtnode->getName());
-    EXPECT_EQ(16, dtree.getNodeCount());
-
-    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_,
-                                                  Name("example.com"),
-                                                  &dtnode));
-    EXPECT_EQ(17, dtree.getNodeCount());
-    // add data to it; also make sure it doesn't have data right now
-    // (otherwise it would leak)
-    EXPECT_EQ(static_cast<int*>(NULL), dtnode->setData(new int(12)));
-
-    // return ALREADYEXISTS, since node "example.com" already has
-    // been explicitly inserted
-    EXPECT_EQ(TestDomainTree::ALREADYEXISTS, dtree.insert(mem_sgmt_,
-                                                        Name("example.com"),
-                                                        &dtnode));
-    EXPECT_EQ(17, dtree.getNodeCount());
-
-    // split the node "d.e.f"
-    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_, Name("k.e.f"),
-                                                  &dtnode));
-    EXPECT_EQ(Name("k"), dtnode->getName());
-    EXPECT_EQ(19, dtree.getNodeCount());
-
-    // split the node "g.h"
-    EXPECT_EQ(TestDomainTree::ALREADYEXISTS, dtree.insert(mem_sgmt_, Name("h"),
-                                                        &dtnode));
-    EXPECT_EQ(Name("h"), dtnode->getName());
-    EXPECT_EQ(20, dtree.getNodeCount());
-
-    // add child domain
-    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_,
-                                                  Name("m.p.w.y.d.e.f"),
-                                                  &dtnode));
-    EXPECT_EQ(Name("m"), dtnode->getName());
-    EXPECT_EQ(21, dtree.getNodeCount());
-    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_,
-                                                  Name("n.p.w.y.d.e.f"),
-                                                  &dtnode));
-    EXPECT_EQ(Name("n"), dtnode->getName());
-    EXPECT_EQ(22, dtree.getNodeCount());
-
-    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_, Name("l.a"),
-                                                  &dtnode));
-    EXPECT_EQ(Name("l"), dtnode->getName());
-    EXPECT_EQ(23, dtree.getNodeCount());
-
-    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_, Name("r.d.e.f"),
-                                                  &dtnode));
-    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_, Name("s.d.e.f"),
-                                                  &dtnode));
-    EXPECT_EQ(25, dtree.getNodeCount());
-
-    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_,
-                                                  Name("h.w.y.d.e.f"),
-                                                  &dtnode));
-
-    // add more nodes one by one to cover leftRotate and rightRotate
-    EXPECT_EQ(TestDomainTree::ALREADYEXISTS, dtree.insert(mem_sgmt_, Name("f"),
-                                                        &dtnode));
-    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_, Name("m"),
-                                                  &dtnode));
-    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_, Name("nm"),
-                                                  &dtnode));
-    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_, Name("om"),
-                                                  &dtnode));
-    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_, Name("k"),
-                                                  &dtnode));
-    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_, Name("l"),
-                                                  &dtnode));
-    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_, Name("fe"),
-                                                  &dtnode));
-    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_, Name("ge"),
-                                                  &dtnode));
-    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_, Name("i"),
-                                                  &dtnode));
-    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_, Name("ae"),
-                                                  &dtnode));
-    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_, Name("n"),
-                                                  &dtnode));
-}
-
-TEST_F(DomainTreeTest, subTreeRoot) {
-    // This is a testcase for a particular issue that went unchecked in
-    // #2089's implementation, but was fixed in #2092. The issue was
-    // that when a node was fissioned, FLAG_SUBTREE_ROOT was not being
-    // copied correctly.
-
-    EXPECT_EQ(TestDomainTree::ALREADYEXISTS,
-              dtree_expose_empty_node.insert(mem_sgmt_, Name("d.e.f"),
-                                              &dtnode));
-    EXPECT_EQ(TestDomainTree::SUCCESS,
-              dtree_expose_empty_node.insert(mem_sgmt_, Name("0"),
-                                              &dtnode));
-    EXPECT_EQ(TestDomainTree::SUCCESS,
-              dtree_expose_empty_node.insert(mem_sgmt_, Name("example.com"),
-                                              &dtnode));
-    EXPECT_EQ(TestDomainTree::ALREADYEXISTS,
-              dtree_expose_empty_node.insert(mem_sgmt_, Name("example.com"),
-                                              &dtnode));
-    EXPECT_EQ(TestDomainTree::SUCCESS,
-              dtree_expose_empty_node.insert(mem_sgmt_, Name("k.e.f"),
-                                              &dtnode));
-
-    // "g.h" is not a subtree root
-    EXPECT_EQ(TestDomainTree::EXACTMATCH,
-              dtree_expose_empty_node.find(Name("g.h"), &dtnode));
-    EXPECT_FALSE(dtnode->getFlag(TestDomainTreeNode::FLAG_SUBTREE_ROOT));
-
-    // fission the node "g.h"
-    EXPECT_EQ(TestDomainTree::ALREADYEXISTS,
-              dtree_expose_empty_node.insert(mem_sgmt_, Name("h"),
-                                              &dtnode));
-
-    // the node "h" (h.down_ -> "g") should not be a subtree root. "g"
-    // should be a subtree root.
-    EXPECT_FALSE(dtnode->getFlag(TestDomainTreeNode::FLAG_SUBTREE_ROOT));
-
-    // "g.h" should be a subtree root now.
-    EXPECT_EQ(TestDomainTree::EXACTMATCH,
-              dtree_expose_empty_node.find(Name("g.h"), &dtnode));
-    EXPECT_TRUE(dtnode->getFlag(TestDomainTreeNode::FLAG_SUBTREE_ROOT));
-}
-
-TEST_F(DomainTreeTest, additionalNodeFission) {
-    // These are additional nodeFission tests added by #2054's rewrite
-    // of DomainTree::nodeFission(). These test specific corner cases that
-    // are not covered by other tests.
-
-    // Insert "t.0" (which becomes the left child of its parent)
-    EXPECT_EQ(TestDomainTree::SUCCESS,
-              dtree_expose_empty_node.insert(mem_sgmt_, Name("t.0"),
-                                             &dtnode));
-
-    // "t.0" is not a subtree root
-    EXPECT_EQ(TestDomainTree::EXACTMATCH,
-              dtree_expose_empty_node.find(Name("t.0"), &dtnode));
-    EXPECT_FALSE(dtnode->getFlag(TestDomainTreeNode::FLAG_SUBTREE_ROOT));
-
-    // fission the node "t.0"
-    EXPECT_EQ(TestDomainTree::ALREADYEXISTS,
-              dtree_expose_empty_node.insert(mem_sgmt_, Name("0"),
-                                             &dtnode));
-
-    // the node "0" ("0".down_ -> "t") should not be a subtree root. "t"
-    // should be a subtree root.
-    EXPECT_FALSE(dtnode->getFlag(TestDomainTreeNode::FLAG_SUBTREE_ROOT));
-
-    // "t.0" should be a subtree root now.
-    EXPECT_EQ(TestDomainTree::EXACTMATCH,
-              dtree_expose_empty_node.find(Name("t.0"), &dtnode));
-    EXPECT_TRUE(dtnode->getFlag(TestDomainTreeNode::FLAG_SUBTREE_ROOT));
-}
-
-TEST_F(DomainTreeTest, findName) {
-    // find const dtnode
-    // exact match
-    EXPECT_EQ(TestDomainTree::EXACTMATCH, dtree.find(Name("a"), &cdtnode));
-    EXPECT_EQ(Name("a"), cdtnode->getName());
-
-    // not found
-    EXPECT_EQ(TestDomainTree::NOTFOUND, dtree.find(Name("d.e.f"), &cdtnode));
-    EXPECT_EQ(TestDomainTree::NOTFOUND, dtree.find(Name("y.d.e.f"), &cdtnode));
-    EXPECT_EQ(TestDomainTree::NOTFOUND, dtree.find(Name("x"), &cdtnode));
-    EXPECT_EQ(TestDomainTree::NOTFOUND, dtree.find(Name("m.n"), &cdtnode));
-
-    // if we expose empty node, we can get the empty node created during insert
-    EXPECT_EQ(TestDomainTree::EXACTMATCH,
-              dtree_expose_empty_node.find(Name("d.e.f"), &cdtnode));
-    EXPECT_EQ(TestDomainTree::EXACTMATCH,
-              dtree_expose_empty_node.find(Name("w.y.d.e.f"), &cdtnode));
-
-    // partial match
-    EXPECT_EQ(TestDomainTree::PARTIALMATCH, dtree.find(Name("m.b"), &cdtnode));
-    EXPECT_EQ(Name("b"), cdtnode->getName());
-    EXPECT_EQ(TestDomainTree::PARTIALMATCH,
-              dtree_expose_empty_node.find(Name("m.d.e.f"), &cdtnode));
-
-    // find dtnode
-    EXPECT_EQ(TestDomainTree::EXACTMATCH, dtree.find(Name("q.w.y.d.e.f"),
-                                                   &dtnode));
-    EXPECT_EQ(Name("q"), dtnode->getName());
-}
-
-TEST_F(DomainTreeTest, findError) {
-    // For the version that takes a node chain, the chain must be empty.
-    TestDomainTreeNodeChain chain;
-    EXPECT_EQ(TestDomainTree::EXACTMATCH, dtree.find(Name("a"), &cdtnode,
-                                                   chain));
-    // trying to reuse the same chain.  it should result in an exception.
-    EXPECT_THROW(dtree.find(Name("a"), &cdtnode, chain),
-                 BadValue);
-}
-
-TEST_F(DomainTreeTest, flags) {
-    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_,
-                                                  Name("flags.example"),
-                                                  &dtnode));
-
-    // by default, flags are all off
-    EXPECT_FALSE(dtnode->getFlag(TestDomainTreeNode::FLAG_CALLBACK));
-
-    // set operation, by default it enables the flag
-    dtnode->setFlag(TestDomainTreeNode::FLAG_CALLBACK);
-    EXPECT_TRUE(dtnode->getFlag(TestDomainTreeNode::FLAG_CALLBACK));
-
-    // try disable the flag explicitly
-    dtnode->setFlag(TestDomainTreeNode::FLAG_CALLBACK, false);
-    EXPECT_FALSE(dtnode->getFlag(TestDomainTreeNode::FLAG_CALLBACK));
-
-    // try enable the flag explicitly
-    dtnode->setFlag(TestDomainTreeNode::FLAG_CALLBACK, true);
-    EXPECT_TRUE(dtnode->getFlag(TestDomainTreeNode::FLAG_CALLBACK));
-
-    // setting an unknown flag will trigger an exception
-    EXPECT_THROW(dtnode->setFlag(static_cast<TestDomainTreeNode::Flags>(2), true),
-                 isc::InvalidParameter);
-}
-
-bool
-testCallback(const TestDomainTreeNode&, bool* callback_checker) {
-    *callback_checker = true;
-    return (false);
-}
-
-template <typename T>
-void
-performCallbackTest(TestDomainTree& dtree,
-                    util::MemorySegmentLocal& mem_sgmt,
-                    const T& name_called,
-                    const T& name_not_called)
-{
-    TestDomainTreeNode* dtnode;
-    const TestDomainTreeNode* cdtnode;
-
-    // by default callback isn't enabled
-    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt,
-                                                  Name("callback.example"),
-                                                  &dtnode));
-    EXPECT_EQ(static_cast<int*>(NULL), dtnode->setData(new int(1)));
-    EXPECT_FALSE(dtnode->getFlag(TestDomainTreeNode::FLAG_CALLBACK));
-
-    // enable/re-disable callback
-    dtnode->setFlag(TestDomainTreeNode::FLAG_CALLBACK);
-    EXPECT_TRUE(dtnode->getFlag(TestDomainTreeNode::FLAG_CALLBACK));
-    dtnode->setFlag(TestDomainTreeNode::FLAG_CALLBACK, false);
-    EXPECT_FALSE(dtnode->getFlag(TestDomainTreeNode::FLAG_CALLBACK));
-
-    // enable again for subsequent tests
-    dtnode->setFlag(TestDomainTreeNode::FLAG_CALLBACK);
-    // add more levels below and above the callback node for partial match.
-    TestDomainTreeNode* subdtnode;
-    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt,
-                                                  Name("sub.callback.example"),
-                                                  &subdtnode));
-    EXPECT_EQ(static_cast<int*>(NULL), subdtnode->setData(new int(2)));
-    TestDomainTreeNode* parentdtnode;
-    EXPECT_EQ(TestDomainTree::ALREADYEXISTS, dtree.insert(mem_sgmt,
-                                                        Name("example"),
-                                                        &parentdtnode));
-    // the child/parent nodes shouldn't "inherit" the callback flag.
-    // "dtnode" may be invalid due to the insertion, so we need to re-find
-    // it.
-    EXPECT_EQ(TestDomainTree::EXACTMATCH, dtree.find(Name("callback.example"),
-                                                   &dtnode));
-    EXPECT_TRUE(dtnode->getFlag(TestDomainTreeNode::FLAG_CALLBACK));
-    EXPECT_FALSE(subdtnode->getFlag(TestDomainTreeNode::FLAG_CALLBACK));
-    EXPECT_FALSE(parentdtnode->getFlag(TestDomainTreeNode::FLAG_CALLBACK));
-
-    // check if the callback is called from find()
-    TestDomainTreeNodeChain node_path1;
-    bool callback_called = false;
-    EXPECT_EQ(TestDomainTree::EXACTMATCH,
-              dtree.find(name_called, &cdtnode, node_path1,
-                          testCallback, &callback_called));
-    EXPECT_TRUE(callback_called);
-
-    // enable callback at the parent node, but it doesn't have data so
-    // the callback shouldn't be called.
-    TestDomainTreeNodeChain node_path2;
-    parentdtnode->setFlag(TestDomainTreeNode::FLAG_CALLBACK);
-    callback_called = false;
-    EXPECT_EQ(TestDomainTree::EXACTMATCH,
-              dtree.find(name_not_called, &cdtnode, node_path2,
-                          testCallback, &callback_called));
-    EXPECT_FALSE(callback_called);
-}
-
-TEST_F(DomainTreeTest, callbackName) {
-    const Name n1("sub.callback.example");
-    const Name n2("callback.example");
-
-    performCallbackTest(dtree, mem_sgmt_, n1, n2);
-}
-
-TEST_F(DomainTreeTest, callbackLabelSequence) {
-    const Name n1("sub.callback.example");
-    const Name n2("callback.example");
-    const LabelSequence ls1(n1);
-    const LabelSequence ls2(n2);
-
-    performCallbackTest(dtree, mem_sgmt_, ls1, ls2);
-}
-
-TEST_F(DomainTreeTest, findInSubTree) {
-    // For the version that takes a node chain, the chain must be empty.
-    DomainTreeNodeChain<int> chain;
-    bool flag;
-
-    // Searching for a non-absolute (right-stripped) label sequence when
-    // chain is empty should throw.
-    const Name n0("w.y.d.e.f");
-    LabelSequence ls0(n0);
-    ls0.stripRight(1);
-    EXPECT_THROW(dtree_expose_empty_node.find(ls0, &cdtnode, chain,
-                                              testCallback, &flag),
-                 isc::BadValue);
-
-    // First, find a sub-tree node
-    chain.clear();
-    const LabelSequence ls1(n0);
-    DomainTree<int>::Result result =
-        dtree_expose_empty_node.find(ls1, &cdtnode, chain,
-                                     testCallback, &flag);
-    EXPECT_EQ(DomainTree<int>::EXACTMATCH, result);
-    EXPECT_EQ(n0, chain.getAbsoluteName());
-
-    // Searching for an absolute label sequence when chain is already
-    // populated should throw.
-    const Name n2a("o");
-    const LabelSequence ls2a(n2a);
-    EXPECT_THROW(dtree_expose_empty_node.find(ls2a, &cdtnode, chain,
-                                              testCallback, &flag),
-                 isc::BadValue);
-
-    // Now, find "o.w.y.d.e.f." by right-stripping the "w.y.d.e.f."
-    // suffix to "o" (non-absolute).
-    const Name n2("o.w.y.d.e.f");
-    LabelSequence ls2(n2);
-    ls2.stripRight(6);
-    EXPECT_EQ("o", ls2.toText());
-
-    result = dtree_expose_empty_node.find(ls2, &cdtnode, chain,
-                                          testCallback, &flag);
-    EXPECT_EQ(DomainTree<int>::EXACTMATCH, result);
-    EXPECT_EQ(n2, chain.getAbsoluteName());
-
-    // Another test. Start with "d.e.f." node.
-    chain.clear();
-    const Name n3("d.e.f");
-    const LabelSequence ls3(n3);
-    result =
-        dtree_expose_empty_node.find(ls3, &cdtnode, chain,
-                                     testCallback, &flag);
-    EXPECT_EQ(DomainTree<int>::EXACTMATCH, result);
-    EXPECT_EQ(n3, chain.getAbsoluteName());
-
-    // Now, find "o.w.y.d.e.f." by right-stripping the "w.y.d.e.f."
-    // suffix to "o.w.y" (non-absolute).
-    const Name n4("o.w.y.d.e.f");
-    LabelSequence ls4(n2);
-    ls4.stripRight(4);
-    EXPECT_EQ("o.w.y", ls4.toText());
-
-    result = dtree_expose_empty_node.find(ls4, &cdtnode, chain,
-                                          testCallback, &flag);
-    EXPECT_EQ(DomainTree<int>::EXACTMATCH, result);
-    EXPECT_EQ(n4, chain.getAbsoluteName());
-}
-
-TEST_F(DomainTreeTest, findInSubTreeSameLabelSequence) {
-    // For the version that takes a node chain, the chain must be empty.
-    DomainTreeNodeChain<int> chain;
-    bool flag;
-
-    const Name n1("c.g.h");
-
-    // First insert a "c.g.h." node.
-    dtree_expose_empty_node.insert(mem_sgmt_, n1, &dtnode);
-
-    /* Now, the tree looks like:
-     *
-     *             .
-     *             |
-     *             b
-     *           /   \
-     *          a    d.e.f
-     *              /  |  \____
-     *             c   |       \
-     *                 |        g.h
-     *                 |         |
-     *                w.y        i
-     *              /  |  \     / \
-     *             x   |   z   c   k
-     *                 |   |
-     *                 p   j
-     *               /   \
-     *              o     q
-     */
-
-    // Make a non-absolute label sequence. We will search for this same
-    // sequence in two places in the tree.
-    LabelSequence ls1(n1);
-    ls1.stripRight(3);
-    EXPECT_EQ("c", ls1.toText());
-
-    // First, find "g.h."
-    const Name n2("g.h");
-    const LabelSequence ls2(n2);
-    DomainTree<int>::Result result =
-        dtree_expose_empty_node.find(ls2, &cdtnode, chain,
-                                     testCallback, &flag);
-    EXPECT_EQ(DomainTree<int>::EXACTMATCH, result);
-    EXPECT_EQ(n2, chain.getAbsoluteName());
-
-    // Now, find "c.g.h." by searching just the non-absolute ls1 label
-    // sequence.
-    result = dtree_expose_empty_node.find(ls1, &cdtnode, chain,
-                                          testCallback, &flag);
-    EXPECT_EQ(DomainTree<int>::EXACTMATCH, result);
-    EXPECT_EQ(n1, chain.getAbsoluteName());
-
-    // Now, find "." (the root node)
-    chain.clear();
-    const Name n3(".");
-    const LabelSequence ls3(n3);
-    result =
-        dtree_expose_empty_node.find(ls3, &cdtnode, chain,
-                                     testCallback, &flag);
-    EXPECT_EQ(DomainTree<int>::EXACTMATCH, result);
-    EXPECT_EQ(n3, chain.getAbsoluteName());
-
-    // Now, find "c." by searching just the non-absolute ls1 label
-    // sequence.
-    result = dtree_expose_empty_node.find(ls1, &cdtnode, chain,
-                                          testCallback, &flag);
-    EXPECT_EQ(DomainTree<int>::EXACTMATCH, result);
-    EXPECT_EQ(Name("c."), chain.getAbsoluteName());
-}
-
-TEST_F(DomainTreeTest, chainLevel) {
-    TestDomainTreeNodeChain chain;
-
-    // by default there should be no level in the chain.
-    EXPECT_EQ(0, chain.getLevelCount());
-
-    // insert one node to the tree and find it.  there should be exactly
-    // one level in the chain.
-    TreeHolder tree_holder(mem_sgmt_, TestDomainTree::create(mem_sgmt_, true));
-    TestDomainTree& tree(*tree_holder.get());
-    Name node_name(Name::ROOT_NAME());
-    EXPECT_EQ(TestDomainTree::SUCCESS, tree.insert(mem_sgmt_, node_name,
-                                                &dtnode));
-    EXPECT_EQ(TestDomainTree::EXACTMATCH,
-              tree.find(node_name, &cdtnode, chain));
-    EXPECT_EQ(1, chain.getLevelCount());
-
-    // Check the name of the found node (should have '.' as both non-absolute
-    // and absolute name
-    EXPECT_EQ(".", cdtnode->getLabels().toText());
-    EXPECT_EQ(".", cdtnode->getAbsoluteLabels(buf).toText());
-
-    /*
-     * Now creating a possibly deepest tree with MAX_LABELS levels.
-     * it should look like:
-     *           (.)
-     *            |
-     *            a
-     *            |
-     *            a
-     *            : (MAX_LABELS - 1) "a"'s
-     *
-     * then confirm that find() for the deepest name succeeds without any
-     * disruption, and the resulting chain has the expected level.
-     * Note that the root name (".") solely belongs to a single level,
-     * so the levels begin with 2.
-     */
-    for (unsigned int i = 2; i <= Name::MAX_LABELS; ++i) {
-        node_name = Name("a.").concatenate(node_name);
-        EXPECT_EQ(TestDomainTree::SUCCESS, tree.insert(mem_sgmt_, node_name,
-                                                    &dtnode));
-        TestDomainTreeNodeChain found_chain;
-        EXPECT_EQ(TestDomainTree::EXACTMATCH,
-                  tree.find(node_name, &cdtnode, found_chain));
-        EXPECT_EQ(i, found_chain.getLevelCount());
-
-        // The non-absolute name should only have the first label
-        EXPECT_EQ("a", cdtnode->getLabels().toText());
-        // But the absolute name should have all labels
-        EXPECT_EQ(node_name.toText(),
-                  cdtnode->getAbsoluteLabels(buf).toText());
-    }
-
-    // Confirm the last inserted name has the possible maximum length with
-    // maximum label count.  This confirms the dtree and chain level cannot
-    // be larger.
-    EXPECT_EQ(Name::MAX_LABELS, node_name.getLabelCount());
-    EXPECT_THROW(node_name.concatenate(Name("a.")), TooLongName);
-}
-
-TEST_F(DomainTreeTest, getAbsoluteNameError) {
-    // an empty chain isn't allowed.
-    TestDomainTreeNodeChain chain;
-    EXPECT_THROW(chain.getAbsoluteName(), BadValue);
-}
-
-/*
- * The domain order should be:
- * ., a, b, c, d.e.f, x.d.e.f, w.y.d.e.f, o.w.y.d.e.f, p.w.y.d.e.f,
- * q.w.y.d.e.f, z.d.e.f, j.z.d.e.f, g.h, i.g.h, k.g.h
- *             . (no data, can't be found)
- *             |
- *             b
- *           /   \
- *          a    d.e.f
- *              /  |   \
- *             c   |    g.h
- *                 |     |
- *                w.y    i
- *              /  |  \   \
- *             x   |   z   k
- *                 |   |
- *                 p   j
- *               /   \
- *              o     q
- */
-const char* const names[] = {
-    "a", "b", "c", "d.e.f", "x.d.e.f", "w.y.d.e.f", "o.w.y.d.e.f",
-    "p.w.y.d.e.f", "q.w.y.d.e.f", "z.d.e.f", "j.z.d.e.f",
-    "g.h", "i.g.h", "k.g.h"};
-const size_t name_count(sizeof(names) / sizeof(*names));
-
-const char* const upper_node_names[] = {
-    ".", ".", ".", ".", "d.e.f", "d.e.f", "w.y.d.e.f",
-    "w.y.d.e.f", "w.y.d.e.f", "d.e.f", "z.d.e.f",
-    ".", "g.h", "g.h"};
-
-TEST_F(DomainTreeTest, getUpperNode) {
-    TestDomainTreeNodeChain node_path;
-    const TestDomainTreeNode* node = NULL;
-    EXPECT_EQ(TestDomainTree::EXACTMATCH,
-              dtree_expose_empty_node.find(Name(names[0]),
-                                            &node,
-                                            node_path));
-    for (int i = 0; i < name_count; ++i) {
-        EXPECT_NE(static_cast<void*>(NULL), node);
-
-        const TestDomainTreeNode* upper_node = node->getUpperNode();
-        if (upper_node_names[i] != NULL) {
-            const TestDomainTreeNode* upper_node2 = NULL;
-            EXPECT_EQ(TestDomainTree::EXACTMATCH,
-                      dtree_expose_empty_node.find(Name(upper_node_names[i]),
-                                                    &upper_node2));
-            EXPECT_NE(static_cast<void*>(NULL), upper_node2);
-            EXPECT_EQ(upper_node, upper_node2);
-        } else {
-            EXPECT_EQ(static_cast<void*>(NULL), upper_node);
-        }
-
-        node = dtree_expose_empty_node.nextNode(node_path);
-    }
-
-    // We should have reached the end of the tree.
-    EXPECT_EQ(static_cast<void*>(NULL), node);
-}
-
-TEST_F(DomainTreeTest, nextNode) {
-    TestDomainTreeNodeChain node_path;
-    const TestDomainTreeNode* node = NULL;
-    EXPECT_EQ(TestDomainTree::EXACTMATCH,
-              dtree.find(Name(names[0]), &node, node_path));
-    for (int i = 0; i < name_count; ++i) {
-        EXPECT_NE(static_cast<void*>(NULL), node);
-        EXPECT_EQ(Name(names[i]), node_path.getAbsoluteName());
-        node = dtree.nextNode(node_path);
-    }
-
-    // We should have reached the end of the tree.
-    EXPECT_EQ(static_cast<void*>(NULL), node);
-}
-
-// Just walk using previousNode until the beginning of the tree and check it is
-// OK
-//
-// dtree - the tree to walk
-// node - result of previous call to find(), starting position of the walk
-// node_path - the path from the previous call to find(), will be modified
-// chain_length - the number of names that should be in the chain to be walked
-//   (0 means it should be empty, 3 means 'a', 'b' and 'c' should be there -
-//   this is always from the beginning of the names[] list).
-// skip_first - if this is false, the node should already contain the node with
-//   the first name of the chain. If it is true, the node should be NULL
-//   (true is for finds that return no match, false for the ones that return
-//   match)
-void
-previousWalk(TestDomainTree& dtree, const TestDomainTreeNode* node,
-             TestDomainTreeNodeChain& node_path, size_t chain_length,
-             bool skip_first)
-{
-    if (skip_first) {
-        // If the first is not found, this is supposed to be NULL and we skip
-        // it in our checks.
-        EXPECT_EQ(static_cast<void*>(NULL), node);
-        node = dtree.previousNode(node_path);
-    }
-    for (size_t i(chain_length); i > 0; --i) {
-        EXPECT_NE(static_cast<void*>(NULL), node);
-        EXPECT_EQ(Name(names[i - 1]), node_path.getAbsoluteName());
-        // Find the node at the path and check the value is the same
-        // (that it really returns the correct corresponding node)
-        //
-        // The "empty" nodes can not be found
-        if (node->getData()) {
-            const TestDomainTreeNode* node2(NULL);
-            TestDomainTreeNodeChain node_path2;
-            EXPECT_EQ(TestDomainTree::EXACTMATCH,
-                      dtree.find(Name(names[i - 1]), &node2, node_path2));
-            EXPECT_EQ(node, node2);
-        }
-        node = dtree.previousNode(node_path);
-    }
-
-    // We should have reached the start of the tree.
-    ASSERT_NE(static_cast<void*>(NULL), node);
-    EXPECT_EQ(".", node->getLabels().toText());
-
-    // With one more call it results in NULL
-    node = dtree.previousNode(node_path);
-    EXPECT_EQ(static_cast<void*>(NULL), node);
-
-    // Calling previousNode() yet again should still return NULL without
-    // fail.
-    node = dtree.previousNode(node_path);
-    EXPECT_EQ(static_cast<void*>(NULL), node);
-}
-
-// Check the previousNode
-TEST_F(DomainTreeTest, previousNode) {
-    // First, iterate the whole tree from the end to the beginning.
-    TestDomainTreeNodeChain node_path;
-    EXPECT_THROW(dtree.previousNode(node_path), isc::BadValue) <<
-        "Throw before a search was done on the path";
-    const TestDomainTreeNode* node(NULL);
-    {
-        SCOPED_TRACE("Iterate through");
-        EXPECT_EQ(TestDomainTree::EXACTMATCH,
-                  dtree.find(Name(names[name_count - 1]), &node, node_path));
-        previousWalk(dtree, node, node_path, name_count, false);
-        node = NULL;
-        node_path.clear();
-    }
-
-    {
-        SCOPED_TRACE("Iterate from the middle");
-        // Now, start somewhere in the middle, but within the real node.
-        EXPECT_EQ(TestDomainTree::EXACTMATCH,
-                  dtree.find(Name(names[4]), &node, node_path));
-        previousWalk(dtree, node, node_path, 5, false);
-        node = NULL;
-        node_path.clear();
-    }
-
-    {
-        SCOPED_TRACE("Start at the first");
-        // If we start at the lowest (which is "a"), we get to the beginning
-        // right away.
-        EXPECT_EQ(TestDomainTree::EXACTMATCH,
-                  dtree.find(Name(names[0]), &node, node_path));
-        EXPECT_NE(static_cast<void*>(NULL), node);
-        node = dtree.previousNode(node_path);
-        ASSERT_NE(static_cast<void*>(NULL), node);
-        EXPECT_EQ(".", node->getLabels().toText());
-        node = NULL;
-        node_path.clear();
-    }
-
-    {
-        SCOPED_TRACE("Start before the first");
-        // If we start before the lowest (. < 0. < a.), we should not get a
-        // node.  Its previous node should be the root.
-        EXPECT_EQ(TestDomainTree::NOTFOUND,
-                  dtree.find<void*>(Name("0"), &node, node_path, NULL, NULL));
-        EXPECT_EQ(static_cast<void*>(NULL), node);
-        node = dtree.previousNode(node_path);
-        ASSERT_NE(static_cast<void*>(NULL), node);
-        EXPECT_EQ(".", node->getLabels().toText());
-        node = NULL;
-        node_path.clear();
-    }
-
-    {
-        SCOPED_TRACE("Start after the last");
-        EXPECT_EQ(TestDomainTree::NOTFOUND,
-                  dtree.find(Name("z"), &node, node_path));
-        previousWalk(dtree, node, node_path, name_count, true);
-        node = NULL;
-        node_path.clear();
-    }
-
-    {
-        SCOPED_TRACE("Start below a leaf");
-        // We exit a leaf by going down. We should start by the one
-        // we exited - 'c' (actually, we should get it by the find, as partial
-        // match).
-        EXPECT_EQ(TestDomainTree::PARTIALMATCH,
-                  dtree.find(Name("b.c"), &node, node_path));
-        previousWalk(dtree, node, node_path, 3, false);
-        node = NULL;
-        node_path.clear();
-    }
-
-    {
-        SCOPED_TRACE("Start to the right of a leaf");
-        // When searching for this, we exit the 'x' node to the right side,
-        // so we should go x afterwards.
-
-        // The d.e.f is empty node, so it is hidden by find. Therefore NOTFOUND
-        // and not PARTIALMATCH.
-        EXPECT_EQ(TestDomainTree::NOTFOUND,
-                  dtree.find(Name("xy.d.e.f"), &node, node_path));
-        previousWalk(dtree, node, node_path, 5, true);
-        node = NULL;
-        node_path.clear();
-    }
-
-    {
-        SCOPED_TRACE("Start to the left of a leaf");
-        // This is similar to the previous, but we exit the 'z' leaf to the
-        // left side, so should not visit z at all then.
-
-        // The d.e.f is empty node, so it is hidden by find. Therefore NOTFOUND
-        // and not PARTIALMATCH.
-        EXPECT_EQ(TestDomainTree::NOTFOUND,
-                  dtree.find(Name("yz.d.e.f"), &node, node_path));
-        previousWalk(dtree, node, node_path, 9, true);
-        node = NULL;
-        node_path.clear();
-    }
-
-    {
-        SCOPED_TRACE("Start to the right of a parent");
-        // When searching for this, we exit the 'g.h' node to the right
-        // side, so we should go to g.h's children afterwards.
-
-        // 'g.h' is an empty node, so we get a NOTFOUND and not
-        // PARTIALMATCH.
-        EXPECT_EQ(TestDomainTree::NOTFOUND,
-                  dtree.find(Name("x.h"), &node, node_path));
-        // 'g.h' is the COMMONANCESTOR.
-        EXPECT_EQ(node_path.getLastComparedNode()->getName(), Name("g.h"));
-        EXPECT_EQ(NameComparisonResult::COMMONANCESTOR,
-                  node_path.getLastComparisonResult().getRelation());
-        // find() exits to the right of 'g.h'
-        EXPECT_GT(node_path.getLastComparisonResult().getOrder(), 0);
-        // We then descend into 'i.g.h' and walk all the nodes in the
-        // tree.
-        previousWalk(dtree, node, node_path, name_count, true);
-        node = NULL;
-        node_path.clear();
-    }
-
-    {
-        SCOPED_TRACE("Start inside a wrong node");
-        // The d.e.f is a single node, but we want only part of it. We
-        // should start iterating before it.
-        EXPECT_EQ(TestDomainTree::NOTFOUND,
-                  dtree.find(Name("e.f"), &node, node_path));
-        previousWalk(dtree, node, node_path, 3, true);
-        node = NULL;
-        node_path.clear();
-    }
-
-    {
-        SCOPED_TRACE("Lookup in empty tree");
-        // Just check it doesn't crash, etc.
-        TreeHolder tree_holder(mem_sgmt_, TestDomainTree::create(mem_sgmt_));
-        TestDomainTree& empty_tree(*tree_holder.get());
-        EXPECT_EQ(TestDomainTree::NOTFOUND,
-                  empty_tree.find(Name("x"), &node, node_path));
-        EXPECT_EQ(static_cast<void*>(NULL), node);
-        EXPECT_EQ(static_cast<void*>(NULL),
-                  empty_tree.previousNode(node_path));
-        node = NULL;
-        node_path.clear();
-    }
-}
-
-TEST_F(DomainTreeTest, nextNodeError) {
-    // Empty chain for nextNode() is invalid.
-    TestDomainTreeNodeChain chain;
-    EXPECT_THROW(dtree.nextNode(chain), BadValue);
-}
-
-// A helper function for getLastComparedNode() below.
-void
-comparisonChecks(const TestDomainTreeNodeChain& chain,
-                 int expected_order, int expected_common_labels,
-                 NameComparisonResult::NameRelation expected_reln)
-{
-    if (expected_order > 0) {
-        EXPECT_LT(0, chain.getLastComparisonResult().getOrder());
-    } else if (expected_order < 0) {
-        EXPECT_GT(0, chain.getLastComparisonResult().getOrder());
-    } else {
-        EXPECT_EQ(0, chain.getLastComparisonResult().getOrder());
-    }
-    EXPECT_EQ(expected_common_labels,
-              chain.getLastComparisonResult().getCommonLabels());
-    EXPECT_EQ(expected_reln,
-              chain.getLastComparisonResult().getRelation());
-}
-
-TEST_F(DomainTreeTest, getLastComparedNode) {
-    TestDomainTree& tree = dtree_expose_empty_node; // use the "empty OK" mode
-    TestDomainTreeNodeChain chain;
-
-    // initially there should be no 'last compared'.
-    EXPECT_EQ(static_cast<void*>(NULL), chain.getLastComparedNode());
-
-    // A search for an empty tree should result in no 'last compared', too.
-    TreeHolder tree_holder(mem_sgmt_, TestDomainTree::create(mem_sgmt_));
-    TestDomainTree& empty_tree(*tree_holder.get());
-    EXPECT_EQ(TestDomainTree::NOTFOUND,
-              empty_tree.find(Name("a"), &cdtnode, chain));
-    EXPECT_EQ(static_cast<void*>(NULL), chain.getLastComparedNode());
-    chain.clear();
-
-    const TestDomainTreeNode* expected_node = NULL;
-
-    // Exact match case.  The returned node should be last compared.
-    EXPECT_EQ(TestDomainTree::EXACTMATCH,
-              tree.find(Name("x.d.e.f"), &expected_node, chain));
-    EXPECT_EQ(expected_node, chain.getLastComparedNode());
-    // 1 = # labels of "x" (note: excluding ".")
-    comparisonChecks(chain, 0, 1, NameComparisonResult::EQUAL);
-    chain.clear();
-
-    // Partial match, search stopped at the matching node, which should be
-    // the last compared node.
-    EXPECT_EQ(TestDomainTree::EXACTMATCH,
-              tree.find(Name("k.g.h"), &expected_node));
-    EXPECT_EQ(TestDomainTree::PARTIALMATCH,
-              tree.find(Name("x.k.g.h"), &cdtnode, chain));
-    EXPECT_EQ(expected_node, chain.getLastComparedNode());
-    // k.g.h < x.k.g.h, 1 = # labels of "k"
-    comparisonChecks(chain, 1, 1, NameComparisonResult::SUBDOMAIN);
-    chain.clear();
-
-    // Partial match, search stopped in the subtree below the matching node
-    // after following a left branch.
-    EXPECT_EQ(TestDomainTree::EXACTMATCH,
-              tree.find(Name("x.d.e.f"), &expected_node));
-    EXPECT_EQ(TestDomainTree::PARTIALMATCH,
-              tree.find(Name("a.d.e.f"), &cdtnode, chain));
-    EXPECT_EQ(expected_node, chain.getLastComparedNode());
-    // a < x, no common labels
-    comparisonChecks(chain, -1, 0, NameComparisonResult::NONE);
-    chain.clear();
-
-    // Partial match, search stopped in the subtree below the matching node
-    // after following a right branch.
-    EXPECT_EQ(TestDomainTree::EXACTMATCH,
-              tree.find(Name("z.d.e.f"), &expected_node));
-    EXPECT_EQ(TestDomainTree::PARTIALMATCH,
-              tree.find(Name("zz.d.e.f"), &cdtnode, chain));
-    EXPECT_EQ(expected_node, chain.getLastComparedNode());
-    // zz > z, no common label
-    comparisonChecks(chain, 1, 0, NameComparisonResult::NONE);
-    chain.clear();
-
-    // Partial match, search stopped at a node for a super domain of the
-    // search name in the subtree below the matching node.
-    EXPECT_EQ(TestDomainTree::EXACTMATCH,
-              tree.find(Name("w.y.d.e.f"), &expected_node));
-    EXPECT_EQ(TestDomainTree::PARTIALMATCH,
-              tree.find(Name("y.d.e.f"), &cdtnode, chain));
-    EXPECT_EQ(expected_node, chain.getLastComparedNode());
-    // y < w.y, 1 = # labels of "y"
-    comparisonChecks(chain, -1, 1, NameComparisonResult::SUPERDOMAIN);
-    chain.clear();
-
-    // Partial match, search stopped at a node that share a common ancestor
-    // with the search name in the subtree below the matching node.
-    // (the expected node is the same as the previous case)
-    EXPECT_EQ(TestDomainTree::PARTIALMATCH,
-              tree.find(Name("z.y.d.e.f"), &cdtnode, chain));
-    EXPECT_EQ(expected_node, chain.getLastComparedNode());
-    // z.y > w.y, 1 = # labels of "y"
-    comparisonChecks(chain, 1, 1, NameComparisonResult::COMMONANCESTOR);
-    chain.clear();
-
-    // Search stops in the highest level (under ".") after following a left
-    // branch. (find() still returns PARTIALMATCH due to the top level ".")
-    EXPECT_EQ(TestDomainTree::EXACTMATCH, tree.find(Name("c"), &expected_node));
-    EXPECT_EQ(TestDomainTree::PARTIALMATCH,
-              tree.find(Name("bb"), &cdtnode, chain));
-    EXPECT_EQ(expected_node, chain.getLastComparedNode());
-    // bb < c, no common label
-    comparisonChecks(chain, -1, 0, NameComparisonResult::NONE);
-    chain.clear();
-
-    // Search stops in the highest level (under ".") after following a right
-    // branch. (the expected node is the same as the previous case)
-    EXPECT_EQ(TestDomainTree::PARTIALMATCH,
-              tree.find(Name("d"), &cdtnode, chain));
-    EXPECT_EQ(expected_node, chain.getLastComparedNode());
-    // d > c, no common label
-    comparisonChecks(chain, 1, 0, NameComparisonResult::NONE);
-    chain.clear();
-}
-
-TEST_F(DomainTreeTest, dumpTree) {
-    std::ostringstream str;
-    std::ostringstream str2;
-    dtree.dumpTree(str);
-    str2 << "tree has 15 node(s)\n"
-            ". (black) [invisible] [subtreeroot]\n"
-            "     begin down from .\n"
-            "     b (black) [subtreeroot]\n"
-            "          a (black)\n"
-            "               NULL\n"
-            "               NULL\n"
-            "          d.e.f (black) [invisible]\n"
-            "               begin down from d.e.f\n"
-            "               w.y (black) [invisible] [subtreeroot]\n"
-            "                    begin down from w.y\n"
-            "                    p (black) [subtreeroot]\n"
-            "                         o (red)\n"
-            "                              NULL\n"
-            "                              NULL\n"
-            "                         q (red)\n"
-            "                              NULL\n"
-            "                              NULL\n"
-            "                    end down from w.y\n"
-            "                    x (red)\n"
-            "                         NULL\n"
-            "                         NULL\n"
-            "                    z (red)\n"
-            "                         begin down from z\n"
-            "                         j (black) [subtreeroot]\n"
-            "                              NULL\n"
-            "                              NULL\n"
-            "                         end down from z\n"
-            "                         NULL\n"
-            "                         NULL\n"
-            "               end down from d.e.f\n"
-            "               c (red)\n"
-            "                    NULL\n"
-            "                    NULL\n"
-            "               g.h (red)\n"
-            "                    begin down from g.h\n"
-            "                    i (black) [subtreeroot]\n"
-            "                         NULL\n"
-            "                         k (red)\n"
-            "                              NULL\n"
-            "                              NULL\n"
-            "                    end down from g.h\n"
-            "                    NULL\n"
-            "                    NULL\n"
-            "     end down from .\n"
-            "     NULL\n"
-            "     NULL\n";
-    EXPECT_EQ(str2.str(), str.str());
-}
-
-TEST_F(DomainTreeTest, swap) {
-    // Store info about the first tree
-    std::ostringstream str1;
-    dtree.dumpTree(str1);
-    size_t count1(dtree.getNodeCount());
-
-    // Create second one and store state
-    TreeHolder tree_holder(mem_sgmt_, TestDomainTree::create(mem_sgmt_));
-    TestDomainTree& tree2(*tree_holder.get());
-    TestDomainTreeNode* node;
-    tree2.insert(mem_sgmt_, Name("second"), &node);
-    std::ostringstream str2;
-    tree2.dumpTree(str2);
-
-    // Swap them
-    ASSERT_NO_THROW(tree2.swap(dtree));
-
-    // Check their sizes
-    ASSERT_EQ(1, dtree.getNodeCount());
-    ASSERT_EQ(count1, tree2.getNodeCount());
-
-    // And content
-    std::ostringstream out;
-    dtree.dumpTree(out);
-    ASSERT_EQ(str2.str(), out.str());
-    out.str("");
-    tree2.dumpTree(out);
-    ASSERT_EQ(str1.str(), out.str());
-}
-
-// Matching in the "root zone" may be special (e.g. there's no parent,
-// any domain names should be considered a subdomain of it), so it makes
-// sense to test cases with the root zone explicitly.
-TEST_F(DomainTreeTest, root) {
-    TreeHolder tree_holder(mem_sgmt_, TestDomainTree::create(mem_sgmt_));
-    TestDomainTree& root(*tree_holder.get());
-    root.insert(mem_sgmt_, Name::ROOT_NAME(), &dtnode);
-    EXPECT_EQ(static_cast<int*>(NULL), dtnode->setData(new int(1)));
-
-    EXPECT_EQ(TestDomainTree::EXACTMATCH,
-              root.find(Name::ROOT_NAME(), &cdtnode));
-    EXPECT_EQ(dtnode, cdtnode);
-    EXPECT_EQ(TestDomainTree::PARTIALMATCH,
-              root.find(Name("example.com"), &cdtnode));
-    EXPECT_EQ(dtnode, cdtnode);
-
-    // Insert a new name that better matches the query name.  find() should
-    // find the better one.
-    root.insert(mem_sgmt_, Name("com"), &dtnode);
-    EXPECT_EQ(static_cast<int*>(NULL), dtnode->setData(new int(2)));
-    EXPECT_EQ(TestDomainTree::PARTIALMATCH,
-              root.find(Name("example.com"), &cdtnode));
-    EXPECT_EQ(dtnode, cdtnode);
-
-    // Perform the same tests for the tree that allows matching against empty
-    // nodes.
-    TreeHolder tree_holder_emptyok(mem_sgmt_,
-                                   TestDomainTree::create(mem_sgmt_, true));
-    TestDomainTree& root_emptyok(*tree_holder_emptyok.get());
-    root_emptyok.insert(mem_sgmt_, Name::ROOT_NAME(), &dtnode);
-    EXPECT_EQ(TestDomainTree::EXACTMATCH,
-              root_emptyok.find(Name::ROOT_NAME(), &cdtnode));
-    EXPECT_EQ(dtnode, cdtnode);
-    EXPECT_EQ(TestDomainTree::PARTIALMATCH,
-              root_emptyok.find(Name("example.com"), &cdtnode));
-    EXPECT_EQ(dtnode, cdtnode);
-
-    root.insert(mem_sgmt_, Name("com"), &dtnode);
-    EXPECT_EQ(TestDomainTree::PARTIALMATCH,
-              root.find(Name("example.com"), &cdtnode));
-    EXPECT_EQ(dtnode, cdtnode);
-}
-
-TEST_F(DomainTreeTest, getAbsoluteLabels) {
-    // The full absolute names of the nodes in the tree
-    // with the addition of the explicit root node
-    const char* const domain_names[] = {
-        "c", "b", "a", "x.d.e.f", "z.d.e.f", "g.h", "i.g.h", "o.w.y.d.e.f",
-        "j.z.d.e.f", "p.w.y.d.e.f", "q.w.y.d.e.f", "k.g.h"};
-    // The names of the nodes themselves, as they end up in the tree
-    const char* const first_labels[] = {
-        "c", "b", "a", "x", "z", "g.h", "i", "o",
-        "j", "p", "q", "k"};
-
-    const int name_count = sizeof(domain_names) / sizeof(domain_names[0]);
-    for (int i = 0; i < name_count; ++i) {
-        EXPECT_EQ(TestDomainTree::EXACTMATCH, dtree.find(Name(domain_names[i]),
-                  &cdtnode));
-
-        // First make sure the names themselves are not absolute
-        const LabelSequence ls(cdtnode->getLabels());
-        EXPECT_EQ(first_labels[i], ls.toText());
-        EXPECT_FALSE(ls.isAbsolute());
-
-        // Now check the absolute names
-        const LabelSequence abs_ls(cdtnode->getAbsoluteLabels(buf));
-        EXPECT_EQ(Name(domain_names[i]).toText(), abs_ls.toText());
-        EXPECT_TRUE(abs_ls.isAbsolute());
-    }
-
-    // Explicitly add and find a root node, to see that getAbsoluteLabels
-    // also works when getLabels() already returns an absolute LabelSequence
-    dtree.insert(mem_sgmt_, Name("."), &dtnode);
-    dtnode->setData(new int(1));
-
-    EXPECT_EQ(TestDomainTree::EXACTMATCH, dtree.find(Name("."), &cdtnode));
-
-    EXPECT_TRUE(cdtnode->getLabels().isAbsolute());
-    EXPECT_EQ(".", cdtnode->getLabels().toText());
-    EXPECT_TRUE(cdtnode->getAbsoluteLabels(buf).isAbsolute());
-    EXPECT_EQ(".", cdtnode->getAbsoluteLabels(buf).toText());
-}
-}
diff --git a/src/lib/datasrc/memory/tests/memory_client_unittest.cc b/src/lib/datasrc/memory/tests/memory_client_unittest.cc
deleted file mode 100644
index fcee0be..0000000
--- a/src/lib/datasrc/memory/tests/memory_client_unittest.cc
+++ /dev/null
@@ -1,767 +0,0 @@
-// 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 <exceptions/exceptions.h>
-
-#include <util/memory_segment_local.h>
-
-#include <dns/name.h>
-#include <dns/rrclass.h>
-#include <dns/masterload.h>
-#include <dns/nsec3hash.h>
-#include <dns/rdata.h>
-#include <dns/rdataclass.h>
-#include <dns/rrsetlist.h>
-#include <dns/rrttl.h>
-#include <dns/masterload.h>
-
-#include <datasrc/result.h>
-#include <datasrc/data_source.h>
-#include <datasrc/memory/zone_data.h>
-#include <datasrc/memory/zone_table.h>
-#include <datasrc/memory/memory_client.h>
-
-#include <testutils/dnsmessage_test.h>
-
-#include "memory_segment_test.h"
-
-#include <gtest/gtest.h>
-
-#include <new>                  // for bad_alloc
-
-using namespace isc::dns;
-using namespace isc::dns::rdata;
-using namespace isc::datasrc;
-using namespace isc::datasrc::memory;
-using namespace isc::testutils;
-
-namespace {
-
-const char* rrset_data[] = {
-    "example.org. 3600 IN SOA ns1.example.org. bugs.x.w.example.org. "
-    "68 3600 300 3600000 3600",
-    "a.example.org. 3600 IN A 192.168.0.1\n" // RRset containing 2 RRs
-    "a.example.org. 3600 IN A 192.168.0.2",
-    "a.example.org. 3600 IN RRSIG A 5 3 3600 20150420235959 20051021000000 "
-    "40430 example.org. FAKEFAKE",
-    "a.example.org. 3600 IN MX 10 mail.example.org.",
-    "a.example.org. 3600 IN RRSIG MX 5 3 3600 20150420235959 20051021000000 "
-    "40430 example.org. FAKEFAKEFAKE",
-    NULL
-};
-
-// RRsets that emulate the "separate RRs" mode.
-const char* rrset_data_separated[] = {
-    "example.org. 3600 IN SOA ns1.example.org. bugs.x.w.example.org. "
-    "68 3600 300 3600000 3600",
-    "a.example.org. 3600 IN A 192.168.0.1", // these two belong to the same
-    "a.example.org. 3600 IN A 192.168.0.2", // RRset, but are separated.
-    NULL
-};
-
-// Similar to the previous one, but with separated RRSIGs
-const char* rrset_data_sigseparated[] = {
-    "example.org. 3600 IN SOA ns1.example.org. bugs.x.w.example.org. "
-    "68 3600 300 3600000 3600",
-    "a.example.org. 3600 IN A 192.168.0.1",
-    "a.example.org. 3600 IN RRSIG A 5 3 3600 20150420235959 20051021000000 "
-    "40430 example.org. FAKEFAKE",
-    "a.example.org. 3600 IN RRSIG A 5 3 3600 20150420235959 20051021000000 "
-    "53535 example.org. FAKEFAKE",
-    NULL
-};
-
-class MockIterator : public ZoneIterator {
-private:
-    MockIterator(const char** rrset_data_ptr, bool pass_empty_rrsig) :
-        rrset_data_ptr_(rrset_data_ptr),
-        pass_empty_rrsig_(pass_empty_rrsig)
-    {
-    }
-
-    const char** rrset_data_ptr_;
-    // If true, emulate an unexpected bogus case where an RRSIG RRset is
-    // returned without the RDATA.  For brevity allow tests tweak it directly.
-    bool pass_empty_rrsig_;
-
-public:
-    virtual ConstRRsetPtr getNextRRset() {
-        if (*rrset_data_ptr_ == NULL) {
-             return (ConstRRsetPtr());
-        }
-
-        ConstRRsetPtr result(textToRRset(*rrset_data_ptr_,
-                                         RRClass::IN(), Name("example.org")));
-        if (pass_empty_rrsig_ && result->getType() == RRType::RRSIG()) {
-            result.reset(new RRset(result->getName(), result->getClass(),
-                                   result->getType(), result->getTTL()));
-        }
-        ++rrset_data_ptr_;
-
-        return (result);
-    }
-
-    virtual ConstRRsetPtr getSOA() const {
-        isc_throw(isc::NotImplemented, "Not implemented");
-    }
-
-    static ZoneIteratorPtr makeIterator(const char** rrset_data_ptr,
-                                        bool pass_empty_rrsig = false)
-    {
-        return (ZoneIteratorPtr(new MockIterator(rrset_data_ptr,
-                                                 pass_empty_rrsig)));
-    }
-};
-
-class MemoryClientTest : public ::testing::Test {
-protected:
-    MemoryClientTest() : zclass_(RRClass::IN()),
-                         client_(new InMemoryClient(mem_sgmt_, zclass_))
-    {}
-    ~MemoryClientTest() {
-        if (client_ != NULL) {
-            delete client_;
-        }
-    }
-    void TearDown() {
-        delete client_;
-        client_ = NULL;
-        EXPECT_TRUE(mem_sgmt_.allMemoryDeallocated()); // catch any leak here.
-    }
-    const RRClass zclass_;
-    test::MemorySegmentTest mem_sgmt_;
-    InMemoryClient* client_;
-};
-
-TEST_F(MemoryClientTest, loadRRsetDoesntMatchOrigin) {
-    // Attempting to load example.org to example.com zone should result
-    // in an exception.
-    EXPECT_THROW(client_->load(Name("example.com"),
-                               TEST_DATA_DIR "/example.org-empty.zone"),
-                 MasterLoadError);
-}
-
-TEST_F(MemoryClientTest, loadErrorsInParsingZoneMustNotLeak1) {
-    // Attempting to load broken example.org zone should result in an
-    // exception. This should not leak ZoneData and other such
-    // allocations.
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR "/example.org-broken1.zone"),
-                 MasterLoadError);
-    // Teardown checks for memory segment leaks
-}
-
-TEST_F(MemoryClientTest, loadErrorsInParsingZoneMustNotLeak2) {
-    // Attempting to load broken example.org zone should result in an
-    // exception. This should not leak ZoneData and other such
-    // allocations.
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR "/example.org-broken2.zone"),
-                 MasterLoadError);
-    // Teardown checks for memory segment leaks
-}
-
-TEST_F(MemoryClientTest, loadNonExistentZoneFile) {
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR "/somerandomfilename"),
-                 MasterLoadError);
-    // Teardown checks for memory segment leaks
-}
-
-TEST_F(MemoryClientTest, loadEmptyZoneFileThrows) {
-    // When an empty zone file is loaded, the origin doesn't even have
-    // an SOA RR. This condition should be avoided, and hence load()
-    // should throw when an empty zone is loaded.
-
-    EXPECT_EQ(0, client_->getZoneCount());
-
-    EXPECT_THROW(client_->load(Name("."),
-                               TEST_DATA_DIR "/empty.zone"),
-                 InMemoryClient::EmptyZone);
-
-    EXPECT_EQ(0, client_->getZoneCount());
-
-    // Teardown checks for memory segment leaks
-}
-
-TEST_F(MemoryClientTest, load) {
-    // This is a simple load check for a "full" and correct zone that
-    // should not result in any exceptions.
-    client_->load(Name("example.org"),
-                  TEST_DATA_DIR "/example.org.zone");
-}
-
-TEST_F(MemoryClientTest, loadFromIterator) {
-    client_->load(Name("example.org"),
-                  *MockIterator::makeIterator(rrset_data));
-
-    ZoneIteratorPtr iterator(client_->getIterator(Name("example.org")));
-
-    // First we have the SOA
-    ConstRRsetPtr rrset(iterator->getNextRRset());
-    EXPECT_TRUE(rrset);
-    EXPECT_EQ(RRType::SOA(), rrset->getType());
-
-    // RRType::MX() RRset
-    rrset = iterator->getNextRRset();
-    EXPECT_TRUE(rrset);
-    EXPECT_EQ(RRType::MX(), rrset->getType());
-    EXPECT_EQ(1, rrset->getRRsigDataCount()); // this RRset is signed
-
-    // RRType::A() RRset
-    rrset = iterator->getNextRRset();
-    EXPECT_TRUE(rrset);
-    EXPECT_EQ(RRType::A(), rrset->getType());
-    EXPECT_EQ(1, rrset->getRRsigDataCount()); // also signed
-
-    // There's nothing else in this iterator
-    EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
-
-    // Iterating past the end should result in an exception
-    EXPECT_THROW(iterator->getNextRRset(), isc::Unexpected);
-
-    // Loading the zone with an iterator separating RRs of the same RRset
-    // will fail because the resulting sequence doesn't meet assumptions of
-    // the (current) in-memory implementation.
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               *MockIterator::makeIterator(
-                                   rrset_data_separated)),
-                 InMemoryClient::AddError);
-
-    // Similar to the previous case, but with separated RRSIGs.
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               *MockIterator::makeIterator(
-                                   rrset_data_sigseparated)),
-                 InMemoryClient::AddError);
-
-    // Emulating bogus iterator implementation that passes empty RRSIGs.
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               *MockIterator::makeIterator(rrset_data, true)),
-                 isc::Unexpected);
-}
-
-TEST_F(MemoryClientTest, loadMemoryAllocationFailures) {
-    // Just to check that things get cleaned up
-
-    for (int i = 1; i < 16; i++) {
-        mem_sgmt_.setThrowCount(i);
-        EXPECT_THROW(client_->load(Name("example.org"),
-                                   TEST_DATA_DIR "/example.org.zone"),
-                     std::bad_alloc);
-    }
-    // Teardown checks for memory segment leaks
-}
-
-TEST_F(MemoryClientTest, loadNSEC3Signed) {
-    client_->load(Name("example.org"),
-                  TEST_DATA_DIR "/example.org-nsec3-signed.zone");
-}
-
-TEST_F(MemoryClientTest, loadNSEC3SignedNoParam) {
-    client_->load(Name("example.org"),
-                  TEST_DATA_DIR "/example.org-nsec3-signed-no-param.zone");
-}
-
-TEST_F(MemoryClientTest, loadReloadZone) {
-    // Because we reload the same zone, also check that the zone count
-    // doesn't increase.
-    EXPECT_EQ(0, client_->getZoneCount());
-
-    client_->load(Name("example.org"),
-                  TEST_DATA_DIR "/example.org-empty.zone");
-    EXPECT_EQ(1, client_->getZoneCount());
-
-    // Reload zone with same data
-
-    client_->load(Name("example.org"),
-                  client_->getFileName(Name("example.org")));
-    EXPECT_EQ(1, client_->getZoneCount());
-
-    isc::datasrc::memory::ZoneTable::FindResult
-        result(client_->findZone2(Name("example.org")));
-    EXPECT_EQ(result::SUCCESS, result.code);
-    EXPECT_NE(static_cast<ZoneData*>(NULL),
-              result.zone_data);
-
-    /* Check SOA */
-    const ZoneNode* node = result.zone_data->getOriginNode();
-    EXPECT_NE(static_cast<const ZoneNode*>(NULL), node);
-
-    const RdataSet* set = node->getData();
-    EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
-    EXPECT_EQ(RRType::SOA(), set->type);
-
-    set = set->getNext();
-    EXPECT_EQ(static_cast<const RdataSet*>(NULL), set);
-
-    /* Check ns1.example.org */
-    const ZoneTree& tree = result.zone_data->getZoneTree();
-    ZoneTree::Result zresult(tree.find(Name("ns1.example.org"), &node));
-    EXPECT_NE(ZoneTree::EXACTMATCH, zresult);
-
-    // Reload zone with different data
-
-    client_->load(Name("example.org"),
-                  TEST_DATA_DIR "/example.org-rrsigs.zone");
-    EXPECT_EQ(1, client_->getZoneCount());
-
-    isc::datasrc::memory::ZoneTable::FindResult
-        result2(client_->findZone2(Name("example.org")));
-    EXPECT_EQ(result::SUCCESS, result2.code);
-    EXPECT_NE(static_cast<ZoneData*>(NULL),
-              result2.zone_data);
-
-    /* Check SOA */
-    node = result2.zone_data->getOriginNode();
-    EXPECT_NE(static_cast<const ZoneNode*>(NULL), node);
-
-    set = node->getData();
-    EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
-    EXPECT_EQ(RRType::SOA(), set->type);
-
-    set = set->getNext();
-    EXPECT_EQ(static_cast<const RdataSet*>(NULL), set);
-
-    /* Check ns1.example.org */
-    const ZoneTree& tree2 = result2.zone_data->getZoneTree();
-    ZoneTree::Result zresult2(tree2.find(Name("ns1.example.org"), &node));
-    EXPECT_EQ(ZoneTree::EXACTMATCH, zresult2);
-    EXPECT_NE(static_cast<const ZoneNode*>(NULL), node);
-
-    set = node->getData();
-    EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
-    EXPECT_EQ(RRType::AAAA(), set->type);
-
-    set = set->getNext();
-    EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
-    EXPECT_EQ(RRType::A(), set->type);
-
-    set = set->getNext();
-    EXPECT_EQ(static_cast<const RdataSet*>(NULL), set);
-
-    // Teardown checks for memory segment leaks
-}
-
-TEST_F(MemoryClientTest, loadDuplicateType) {
-    // This should not result in any exceptions:
-    client_->load(Name("example.org"),
-                  TEST_DATA_DIR "/example.org-duplicate-type.zone");
-
-    // This should throw:
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR
-                               "/example.org-duplicate-type-bad.zone"),
-                 InMemoryClient::AddError);
-    // Teardown checks for memory segment leaks
-}
-
-TEST_F(MemoryClientTest, loadMultipleCNAMEThrows) {
-    // Multiple CNAME RRs should throw.
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR
-                               "/example.org-multiple-cname.zone"),
-                 InMemoryClient::AddError);
-    // Teardown checks for memory segment leaks
-}
-
-TEST_F(MemoryClientTest, loadMultipleDNAMEThrows) {
-    // Multiple DNAME RRs should throw.
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR
-                               "/example.org-multiple-dname.zone"),
-                 InMemoryClient::AddError);
-    // Teardown checks for memory segment leaks
-}
-
-TEST_F(MemoryClientTest, loadMultipleNSEC3Throws) {
-    // Multiple NSEC3 RRs should throw.
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR
-                               "/example.org-multiple-nsec3.zone"),
-                 InMemoryClient::AddError);
-    // Teardown checks for memory segment leaks
-}
-
-TEST_F(MemoryClientTest, loadMultipleNSEC3PARAMThrows) {
-    // Multiple NSEC3PARAM RRs should throw.
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR
-                               "/example.org-multiple-nsec3param.zone"),
-                 InMemoryClient::AddError);
-    // Teardown checks for memory segment leaks
-}
-
-TEST_F(MemoryClientTest, loadOutOfZoneThrows) {
-    // Out of zone names should throw.
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR
-                               "/example.org-out-of-zone.zone"),
-                 MasterLoadError);
-    // Teardown checks for memory segment leaks
-}
-
-TEST_F(MemoryClientTest, loadWildcardNSThrows) {
-    // Wildcard NS names should throw
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR
-                               "/example.org-wildcard-ns.zone"),
-                 InMemoryClient::AddError);
-    // Teardown checks for memory segment leaks
-}
-
-TEST_F(MemoryClientTest, loadWildcardDNAMEThrows) {
-    // Wildcard DNAME names should throw
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR
-                               "/example.org-wildcard-dname.zone"),
-                 InMemoryClient::AddError);
-    // Teardown checks for memory segment leaks
-}
-
-TEST_F(MemoryClientTest, loadWildcardNSEC3Throws) {
-    // Wildcard NSEC3 names should throw
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR
-                               "/example.org-wildcard-nsec3.zone"),
-                 InMemoryClient::AddError);
-    // Teardown checks for memory segment leaks
-}
-
-TEST_F(MemoryClientTest, loadNSEC3WithFewerLabelsThrows) {
-    // NSEC3 names with labels != (origin_labels + 1) should throw
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR
-                               "/example.org-nsec3-fewer-labels.zone"),
-                 InMemoryClient::AddError);
-    // Teardown checks for memory segment leaks
-}
-
-TEST_F(MemoryClientTest, loadNSEC3WithMoreLabelsThrows) {
-    // NSEC3 names with labels != (origin_labels + 1) should throw
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR
-                               "/example.org-nsec3-more-labels.zone"),
-                 InMemoryClient::AddError);
-    // Teardown checks for memory segment leaks
-}
-
-TEST_F(MemoryClientTest, loadCNAMEAndNotNSECThrows) {
-    // CNAME and not NSEC should throw
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR
-                               "/example.org-cname-and-not-nsec-1.zone"),
-                 InMemoryClient::AddError);
-
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR
-                               "/example.org-cname-and-not-nsec-2.zone"),
-                 InMemoryClient::AddError);
-
-    // Teardown checks for memory segment leaks
-}
-
-TEST_F(MemoryClientTest, loadDNAMEAndNSApex1) {
-    // DNAME + NS (apex) is OK
-    client_->load(Name("example.org"),
-                  TEST_DATA_DIR
-                  "/example.org-dname-ns-apex-1.zone");
-    // Teardown checks for memory segment leaks
-}
-
-TEST_F(MemoryClientTest, loadDNAMEAndNSApex2) {
-    // DNAME + NS (apex) is OK (reverse order)
-    client_->load(Name("example.org"),
-                  TEST_DATA_DIR
-                  "/example.org-dname-ns-apex-2.zone");
-    // Teardown checks for memory segment leaks
-}
-
-TEST_F(MemoryClientTest, loadDNAMEAndNSNonApex1) {
-    // DNAME + NS (non-apex) must throw
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR
-                               "/example.org-dname-ns-nonapex-1.zone"),
-                 InMemoryClient::AddError);
-    // Teardown checks for memory segment leaks
-}
-
-TEST_F(MemoryClientTest, loadDNAMEAndNSNonApex2) {
-    // DNAME + NS (non-apex) must throw (reverse order)
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR
-                               "/example.org-dname-ns-nonapex-2.zone"),
-                 InMemoryClient::AddError);
-    // Teardown checks for memory segment leaks
-}
-
-TEST_F(MemoryClientTest, loadRRSIGFollowsNothing) {
-    // This causes the situation where an RRSIG is added without a covered
-    // RRset.  Such cases are currently rejected.
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR
-                               "/example.org-rrsig-follows-nothing.zone"),
-                 InMemoryClient::AddError);
-    // Teardown checks for memory segment leaks
-}
-
-TEST_F(MemoryClientTest, loadRRSIGs) {
-    client_->load(Name("example.org"),
-                  TEST_DATA_DIR "/example.org-rrsigs.zone");
-    EXPECT_EQ(1, client_->getZoneCount());
-}
-
-TEST_F(MemoryClientTest, loadRRSIGsRdataMixedCoveredTypes) {
-    client_->load(Name("example.org"),
-                  TEST_DATA_DIR "/example.org-rrsigs.zone");
-
-    RRsetPtr rrset(new RRset(Name("example.org"),
-                             RRClass::IN(), RRType::A(), RRTTL(3600)));
-    rrset->addRdata(in::A("192.0.2.1"));
-    rrset->addRdata(in::A("192.0.2.2"));
-
-    RRsetPtr rrsig(new RRset(Name("example.org"), zclass_,
-                             RRType::RRSIG(), RRTTL(300)));
-    rrsig->addRdata(generic::RRSIG("A 5 3 3600 20000101000000 20000201000000 "
-                                   "12345 example.org. FAKEFAKEFAKE"));
-    rrsig->addRdata(generic::RRSIG("NS 5 3 3600 20000101000000 20000201000000 "
-                                   "54321 example.org. FAKEFAKEFAKEFAKE"));
-    rrset->addRRsig(rrsig);
-
-    EXPECT_THROW(client_->add(Name("example.org"), rrset),
-                 InMemoryClient::AddError);
-
-    // Teardown checks for memory segment leaks
-}
-
-TEST_F(MemoryClientTest, getZoneCount) {
-    EXPECT_EQ(0, client_->getZoneCount());
-    client_->load(Name("example.org"), TEST_DATA_DIR "/example.org-empty.zone");
-    EXPECT_EQ(1, client_->getZoneCount());
-}
-
-TEST_F(MemoryClientTest, getFileNameForNonExistentZone) {
-    // Zone "example.org." doesn't exist
-    EXPECT_TRUE(client_->getFileName(Name("example.org.")).empty());
-}
-
-TEST_F(MemoryClientTest, getFileName) {
-    client_->load(Name("example.org"), TEST_DATA_DIR "/example.org-empty.zone");
-    EXPECT_EQ(TEST_DATA_DIR "/example.org-empty.zone",
-              client_->getFileName(Name("example.org")));
-}
-
-TEST_F(MemoryClientTest, getIteratorForNonExistentZone) {
-    // Zone "." doesn't exist
-    EXPECT_THROW(client_->getIterator(Name(".")), DataSourceError);
-}
-
-TEST_F(MemoryClientTest, getIterator) {
-    client_->load(Name("example.org"), TEST_DATA_DIR "/example.org-empty.zone");
-    ZoneIteratorPtr iterator(client_->getIterator(Name("example.org")));
-
-    // First we have the SOA
-    ConstRRsetPtr rrset_soa(iterator->getNextRRset());
-    EXPECT_TRUE(rrset_soa);
-    EXPECT_EQ(RRType::SOA(), rrset_soa->getType());
-
-    // There's nothing else in this iterator
-    EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
-
-    // Iterating past the end should result in an exception
-    EXPECT_THROW(iterator->getNextRRset(), isc::Unexpected);
-}
-
-TEST_F(MemoryClientTest, getIteratorSeparateRRs) {
-    client_->load(Name("example.org"),
-                  TEST_DATA_DIR "/example.org-multiple.zone");
-
-    // separate_rrs = false
-    ZoneIteratorPtr iterator(client_->getIterator(Name("example.org")));
-
-    // First we have the SOA
-    ConstRRsetPtr rrset(iterator->getNextRRset());
-    EXPECT_TRUE(rrset);
-    EXPECT_EQ(RRType::SOA(), rrset->getType());
-
-    // Only one RRType::A() RRset
-    rrset = iterator->getNextRRset();
-    EXPECT_TRUE(rrset);
-    EXPECT_EQ(RRType::A(), rrset->getType());
-
-    // There's nothing else in this zone
-    EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
-
-
-    // separate_rrs = true
-    ZoneIteratorPtr iterator2(client_->getIterator(Name("example.org"), true));
-
-    // First we have the SOA
-    rrset = iterator2->getNextRRset();
-    EXPECT_TRUE(rrset);
-    EXPECT_EQ(RRType::SOA(), rrset->getType());
-
-    // First RRType::A() RRset
-    rrset = iterator2->getNextRRset();
-    EXPECT_TRUE(rrset);
-    EXPECT_EQ(RRType::A(), rrset->getType());
-
-    // Second RRType::A() RRset
-    rrset = iterator2->getNextRRset();
-    EXPECT_TRUE(rrset);
-    EXPECT_EQ(RRType::A(), rrset->getType());
-
-    // There's nothing else in this iterator
-    EXPECT_EQ(ConstRRsetPtr(), iterator2->getNextRRset());
-}
-
-TEST_F(MemoryClientTest, getIteratorGetSOAThrowsNotImplemented) {
-    client_->load(Name("example.org"), TEST_DATA_DIR "/example.org-empty.zone");
-    ZoneIteratorPtr iterator(client_->getIterator(Name("example.org")));
-
-    // This method is not implemented.
-    EXPECT_THROW(iterator->getSOA(), isc::NotImplemented);
-}
-
-TEST_F(MemoryClientTest, addRRsetToNonExistentZoneThrows) {
-    // The zone "example.org" doesn't exist, so we can't add an RRset to
-    // it.
-    RRsetPtr rrset_a(new RRset(Name("example.org"), RRClass::IN(), RRType::A(),
-                               RRTTL(300)));
-    rrset_a->addRdata(rdata::in::A("192.0.2.1"));
-    EXPECT_THROW(client_->add(Name("example.org"), rrset_a), DataSourceError);
-}
-
-TEST_F(MemoryClientTest, addOutOfZoneThrows) {
-    // Out of zone names should throw.
-    client_->load(Name("example.org"),
-                  TEST_DATA_DIR "/example.org-empty.zone");
-
-    RRsetPtr rrset_a(new RRset(Name("a.example.com"),
-                               RRClass::IN(), RRType::A(), RRTTL(300)));
-    rrset_a->addRdata(rdata::in::A("192.0.2.1"));
-
-    EXPECT_THROW(client_->add(Name("example.org"), rrset_a),
-                 OutOfZone);
-    // Teardown checks for memory segment leaks
-}
-
-TEST_F(MemoryClientTest, addNullRRsetThrows) {
-    client_->load(Name("example.org"),
-                  TEST_DATA_DIR "/example.org-rrsigs.zone");
-
-    EXPECT_THROW(client_->add(Name("example.org"), ConstRRsetPtr()),
-                 InMemoryClient::NullRRset);
-
-    // Teardown checks for memory segment leaks
-}
-
-TEST_F(MemoryClientTest, addEmptyRRsetThrows) {
-    client_->load(Name("example.org"),
-                  TEST_DATA_DIR "/example.org-rrsigs.zone");
-
-    RRsetPtr rrset_a(new RRset(Name("example.org"), RRClass::IN(), RRType::A(),
-                               RRTTL(300)));
-    EXPECT_THROW(client_->add(Name("example.org"), rrset_a),
-                 InMemoryClient::AddError);
-
-    // Teardown checks for memory segment leaks
-}
-
-TEST_F(MemoryClientTest, add) {
-    client_->load(Name("example.org"), TEST_DATA_DIR "/example.org-empty.zone");
-
-    // Add another RRset
-    RRsetPtr rrset_a(new RRset(Name("example.org"), RRClass::IN(), RRType::A(),
-                               RRTTL(300)));
-    rrset_a->addRdata(rdata::in::A("192.0.2.1"));
-    client_->add(Name("example.org"), rrset_a);
-
-    ZoneIteratorPtr iterator(client_->getIterator(Name("example.org")));
-
-    // First we have the SOA
-    ConstRRsetPtr rrset(iterator->getNextRRset());
-    EXPECT_TRUE(rrset);
-    EXPECT_EQ(RRType::A(), rrset->getType());
-
-    rrset = iterator->getNextRRset();
-    EXPECT_TRUE(rrset);
-    EXPECT_EQ(RRType::SOA(), rrset->getType());
-
-    // There's nothing else in this zone
-    EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
-}
-
-TEST_F(MemoryClientTest, findZoneThrowsNotImplemented) {
-    // This method is not implemented.
-    EXPECT_THROW(client_->findZone(Name(".")),
-                 isc::NotImplemented);
-}
-
-TEST_F(MemoryClientTest, findZone2) {
-    client_->load(Name("example.org"),
-                  TEST_DATA_DIR "/example.org-rrsigs.zone");
-
-    isc::datasrc::memory::ZoneTable::FindResult
-        result(client_->findZone2(Name("example.com")));
-    EXPECT_EQ(result::NOTFOUND, result.code);
-    EXPECT_EQ(static_cast<ZoneData*>(NULL),
-              result.zone_data);
-
-    isc::datasrc::memory::ZoneTable::FindResult
-        result2(client_->findZone2(Name("example.org")));
-    EXPECT_EQ(result::SUCCESS, result2.code);
-    EXPECT_NE(static_cast<ZoneData*>(NULL),
-              result2.zone_data);
-
-    /* Check SOA */
-    const ZoneNode* node = result2.zone_data->getOriginNode();
-    EXPECT_NE(static_cast<const ZoneNode*>(NULL), node);
-
-    const RdataSet* set = node->getData();
-    EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
-    EXPECT_EQ(RRType::SOA(), set->type);
-
-    set = set->getNext();
-    EXPECT_EQ(static_cast<const RdataSet*>(NULL), set);
-
-    /* Check ns1.example.org */
-    const ZoneTree& tree = result2.zone_data->getZoneTree();
-    ZoneTree::Result result3(tree.find(Name("ns1.example.org"), &node));
-    EXPECT_EQ(ZoneTree::EXACTMATCH, result3);
-    EXPECT_NE(static_cast<const ZoneNode*>(NULL), node);
-
-    set = node->getData();
-    EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
-    EXPECT_EQ(RRType::AAAA(), set->type);
-
-    set = set->getNext();
-    EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
-    EXPECT_EQ(RRType::A(), set->type);
-
-    set = set->getNext();
-    EXPECT_EQ(static_cast<const RdataSet*>(NULL), set);
-}
-
-TEST_F(MemoryClientTest, getUpdaterThrowsNotImplemented) {
-    // This method is not implemented.
-    EXPECT_THROW(client_->getUpdater(Name("."), false, false),
-                 isc::NotImplemented);
-}
-
-TEST_F(MemoryClientTest, getJournalReaderNotImplemented) {
-    // This method is not implemented.
-    EXPECT_THROW(client_->getJournalReader(Name("."), 0, 0),
-                 isc::NotImplemented);
-}
-}
diff --git a/src/lib/datasrc/memory/tests/memory_segment_test.h b/src/lib/datasrc/memory/tests/memory_segment_test.h
deleted file mode 100644
index 3195a9b..0000000
--- a/src/lib/datasrc/memory/tests/memory_segment_test.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// 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.
-
-#ifndef DATASRC_MEMORY_SEGMENT_TEST_H
-#define DATASRC_MEMORY_SEGMENT_TEST_H 1
-
-#include <util/memory_segment_local.h>
-
-#include <cstddef>              // for size_t
-#include <new>                  // for bad_alloc
-
-namespace isc {
-namespace datasrc {
-namespace memory {
-namespace test {
-
-// A special memory segment that can be used for tests.  It normally behaves
-// like a "local" memory segment.  If "throw count" is set to non 0 via
-// setThrowCount(), it continues the normal behavior until the specified
-// number of calls to allocate(), exclusive, and throws an exception at the
-// next call.  For example, if count is set to 3, the next two calls to
-// allocate() will succeed, and the 3rd call will fail with an exception.
-// This segment object can be used after the exception is thrown, and the
-// count is internally reset to 0.
-class MemorySegmentTest : public isc::util::MemorySegmentLocal {
-public:
-    MemorySegmentTest() : throw_count_(0) {}
-    virtual void* allocate(std::size_t size) {
-        if (throw_count_ > 0) {
-            if (--throw_count_ == 0) {
-                throw std::bad_alloc();
-            }
-        }
-        return (isc::util::MemorySegmentLocal::allocate(size));
-    }
-    void setThrowCount(std::size_t count) { throw_count_ = count; }
-
-private:
-    std::size_t throw_count_;
-};
-
-} // namespace test
-} // namespace memory
-} // namespace datasrc
-} // namespace isc
-
-#endif // DATASRC_MEMORY_SEGMENT_TEST_H
-
-// Local Variables:
-// mode: c++
-// End:
diff --git a/src/lib/datasrc/memory/tests/rdata_serialization_unittest.cc b/src/lib/datasrc/memory/tests/rdata_serialization_unittest.cc
deleted file mode 100644
index 12b613a..0000000
--- a/src/lib/datasrc/memory/tests/rdata_serialization_unittest.cc
+++ /dev/null
@@ -1,839 +0,0 @@
-// 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 <exceptions/exceptions.h>
-
-#include <util/buffer.h>
-
-#include <dns/name.h>
-#include <dns/labelsequence.h>
-#include <dns/messagerenderer.h>
-#include <dns/rdata.h>
-#include <dns/rdataclass.h>
-#include <dns/rrclass.h>
-#include <dns/rrtype.h>
-
-#include <datasrc/memory/rdata_serialization.h>
-
-#include <util/unittests/wiredata.h>
-
-#include <gtest/gtest.h>
-
-#include <boost/bind.hpp>
-#include <boost/foreach.hpp>
-
-#include <cstring>
-#include <set>
-#include <string>
-#include <vector>
-
-using namespace isc::dns;
-using namespace isc::dns::rdata;
-using namespace isc::datasrc::memory;
-
-using isc::util::unittests::matchWireData;
-using std::string;
-using std::vector;
-
-// A trick to steal some private definitions of the implementation we use here
-
-namespace isc {
-namespace datasrc{
-namespace memory {
-
-#include "../rdata_serialization_priv.cc"
-
-}
-}
-}
-
-namespace {
-// This defines a tuple of test data used in test_rdata_list below.
-struct TestRdata {
-    const char* const rrclass;  // RR class, textual form
-    const char* const rrtype;   // RR type, textual form
-    const char* const rdata;    // textual RDATA
-    const size_t n_varlen_fields; // expected # of variable-len fields
-};
-
-// This test data consist of (almost) all supported types of RDATA (+ some
-// unusual and corner cases).
-const TestRdata test_rdata_list[] = {
-    {"IN", "A", "192.0.2.1", 0},
-    {"IN", "NS", "ns.example.com", 0},
-    {"IN", "CNAME", "cname.example.com", 0},
-    {"IN", "SOA", "ns.example.com root.example.com 0 0 0 0 0", 0},
-    {"IN", "PTR", "reverse.example.com", 0},
-    {"IN", "HINFO", "\"cpu-info\" \"OS-info\"", 1},
-    {"IN", "MINFO", "root.example.com mbox.example.com", 0},
-    {"IN", "MX", "10 mx.example.com", 0},
-    {"IN", "TXT", "\"test1\" \"test 2\"", 1},
-    {"IN", "RP", "root.example.com. rp-text.example.com", 0},
-    {"IN", "AFSDB", "1 afsdb.example.com", 0},
-    {"IN", "AAAA", "2001:db8::1", 0},
-    {"IN", "SRV", "1 0 10 target.example.com", 0},
-    {"IN", "NAPTR", "100 50 \"s\" \"http\" \"\" _http._tcp.example.com", 1},
-    {"IN", "DNAME", "dname.example.com", 0},
-    {"IN", "DS", "12892 5 2 5F0EB5C777586DE18DA6B5", 1},
-    {"IN", "SSHFP", "1 1 dd465c09cfa51fb45020cc83316fff", 1},
-    // We handle RRSIG separately, so it's excluded from the list
-    {"IN", "NSEC", "next.example.com. A AAAA NSEC RRSIG", 1},
-    {"IN", "DNSKEY", "256 3 5 FAKEFAKE", 1},
-    {"IN", "DHCID", "FAKEFAKE", 1},
-    {"IN", "NSEC3", "1 1 12 AABBCCDD FAKEFAKE A RRSIG", 1},
-    {"IN", "NSEC3PARAM", "1 0 12 AABBCCDD", 1},
-    {"IN", "SPF", "v=spf1 +mx a:colo.example.com/28 -all", 1},
-    {"IN", "DLV", "12892 5 2 5F0EB5C777586DE18DA6B5", 1},
-    {"IN", "TYPE65000", "\\# 3 010203", 1}, // some "custom" type
-    {"IN", "TYPE65535", "\\# 0", 1},        // max RR type, 0-length RDATA
-    {"CH", "A", "\\# 2 0102", 1}, // A RR for non-IN class; varlen data
-    {"CH", "NS", "ns.example.com", 0}, // class CH, generic data
-    {"CH", "TXT", "BIND10", 1},        // ditto
-    {"HS", "A", "\\# 5 0102030405", 1}, // A RR for non-IN class; varlen data
-    {NULL, NULL, NULL, 0}
-};
-
-// The following two functions will be used to generate wire format data
-// from encoded representation of each RDATA.
-void
-renderNameField(MessageRenderer* renderer, bool additional_required,
-                const LabelSequence& labels, RdataNameAttributes attributes)
-{
-    EXPECT_EQ(additional_required, (attributes & NAMEATTR_ADDITIONAL) != 0);
-    renderer->writeName(labels, (attributes & NAMEATTR_COMPRESSIBLE) != 0);
-}
-
-void
-renderDataField(MessageRenderer* renderer, const void* data, size_t data_len) {
-    renderer->writeData(data, data_len);
-}
-
-class RdataSerializationTest : public ::testing::Test {
-protected:
-    RdataSerializationTest() : a_rdata_(createRdata(RRType::A(), RRClass::IN(),
-                                                    "192.0.2.53")),
-                         aaaa_rdata_(createRdata(RRType::AAAA(), RRClass::IN(),
-                                                 "2001:db8::53")),
-                         rrsig_rdata_(createRdata(
-                                          RRType::RRSIG(), RRClass::IN(),
-                                          "A 5 2 3600 20120814220826 "
-                                          "20120715220826 12345 com. FAKE"))
-    {}
-
-    // A wraper for RdataEncoder::encode() with buffer overrun check.
-    void encodeWrapper(size_t data_len);
-
-    // Some commonly used RDATA
-    const ConstRdataPtr a_rdata_;
-    const ConstRdataPtr aaaa_rdata_;
-    const ConstRdataPtr rrsig_rdata_;
-
-    RdataEncoder encoder_;
-    vector<uint8_t> encoded_data_;
-    MessageRenderer expected_renderer_;
-    MessageRenderer actual_renderer_;
-    vector<ConstRdataPtr> rdata_list_;
-};
-
-// There are several ways to decode the data. For one, there are
-// more interfaces uses for RdataReader, and we use our own decoder,
-// to check the actual encoded data.
-//
-// These decoding ways are provided by the template parameter.
-template<class DecoderStyle>
-class RdataEncodeDecodeTest : public RdataSerializationTest {
-public:
-    // This helper test method encodes the given list of RDATAs
-    // (in rdata_list), and then iterates over the data, rendering the fields
-    // in the wire format.  It then compares the wire data with the one
-    // generated by the normal libdns++ interface to see the encoding/decoding
-    // works as intended.
-    void checkEncode(RRClass rrclass, RRType rrtype,
-                     const vector<ConstRdataPtr>& rdata_list,
-                     size_t expected_varlen_fields,
-                     const vector<ConstRdataPtr>& rrsig_list =
-                     vector<ConstRdataPtr>());
-
-    void addRdataCommon(const vector<ConstRdataPtr>& rrsigs);
-    void addRdataMultiCommon(const vector<ConstRdataPtr>& rrsigs);
-};
-
-// Used across more classes and scopes. But it's just uninteresting
-// constant.
-const Name& dummyName2() {
-    static const Name result("example.com");
-    return (result);
-}
-
-bool
-additionalRequired(const RRType& type) {
-    // The set of RR types that require additional section processing.
-    // We'll use it to determine what value should the renderNameField get
-    // and, if the stored attributes are as expected.
-    static std::set<RRType> need_additionals;
-    if (need_additionals.empty()) {
-        need_additionals.insert(RRType::NS());
-        need_additionals.insert(RRType::MX());
-        need_additionals.insert(RRType::SRV());
-    }
-
-    return (need_additionals.find(type) != need_additionals.end());
-}
-
-// A decoder that does not use RdataReader. Not recommended for use,
-// but it allows the tests to check the internals of the data.
-class ManualDecoderStyle {
-public:
-    static void foreachRdataField(RRClass rrclass, RRType rrtype,
-                                  size_t rdata_count,
-                                  const vector<uint8_t>& encoded_data,
-                                  const vector<uint16_t>& varlen_list,
-                                  RdataReader::NameAction name_callback,
-                                  RdataReader::DataAction data_callback)
-    {
-        const RdataEncodeSpec& encode_spec = getRdataEncodeSpec(rrclass,
-                                                                rrtype);
-
-        size_t off = 0;
-        size_t varlen_count = 0;
-        size_t name_count = 0;
-        for (size_t count = 0; count < rdata_count; ++count) {
-            for (size_t i = 0; i < encode_spec.field_count; ++i) {
-                const RdataFieldSpec& field_spec = encode_spec.fields[i];
-                switch (field_spec.type) {
-                    case RdataFieldSpec::FIXEDLEN_DATA:
-                        if (data_callback) {
-                            data_callback(&encoded_data.at(off),
-                                          field_spec.fixeddata_len);
-                        }
-                        off += field_spec.fixeddata_len;
-                        break;
-                    case RdataFieldSpec::VARLEN_DATA:
-                        {
-                            const size_t varlen = varlen_list.at(varlen_count);
-                            if (data_callback && varlen > 0) {
-                                data_callback(&encoded_data.at(off), varlen);
-                            }
-                            off += varlen;
-                            ++varlen_count;
-                            break;
-                        }
-                    case RdataFieldSpec::DOMAIN_NAME:
-                        {
-                            ++name_count;
-                            const LabelSequence labels(&encoded_data.at(off));
-                            if (name_callback) {
-                                name_callback(labels,
-                                              field_spec.name_attributes);
-                            }
-                            off += labels.getSerializedLength();
-                            break;
-                        }
-                }
-            }
-        }
-        assert(name_count == encode_spec.name_count * rdata_count);
-        assert(varlen_count == encode_spec.varlen_count * rdata_count);
-    }
-
-    static void foreachRRSig(const vector<uint8_t>& encoded_data,
-                             const vector<uint16_t>& rrsiglen_list,
-                             RdataReader::DataAction data_callback)
-    {
-        size_t rrsig_totallen = 0;
-        for (vector<uint16_t>::const_iterator it = rrsiglen_list.begin();
-             it != rrsiglen_list.end();
-             ++it) {
-            rrsig_totallen += *it;
-        }
-        assert(encoded_data.size() >= rrsig_totallen);
-
-        const uint8_t* dp = &encoded_data[encoded_data.size() -
-            rrsig_totallen];
-        for (size_t i = 0; i < rrsiglen_list.size(); ++i) {
-            data_callback(dp, rrsiglen_list[i]);
-            dp += rrsiglen_list[i];
-        }
-    }
-
-    static void decode(const isc::dns::RRClass& rrclass,
-                       const isc::dns::RRType& rrtype,
-                       size_t rdata_count,
-                       size_t rrsig_count,
-                       size_t expected_varlen_fields,
-                       // Warning: this test actualy might change the
-                       // encoded_data !
-                       vector<uint8_t>& encoded_data, size_t,
-                       MessageRenderer& renderer)
-    {
-        // If this type of RDATA is expected to contain variable-length fields,
-        // we brute force the encoded data, exploiting our knowledge of actual
-        // encoding, then adjust the encoded data excluding the list of length
-        // fields.  This is ugly, but for tests only.
-        vector<uint16_t> varlen_list;
-        if (expected_varlen_fields > 0) {
-            const size_t varlen_list_size =
-                rdata_count * expected_varlen_fields * sizeof(uint16_t);
-            ASSERT_LE(varlen_list_size, encoded_data.size());
-            varlen_list.resize(rdata_count * expected_varlen_fields);
-            std::memcpy(&varlen_list[0], &encoded_data[0], varlen_list_size);
-            encoded_data.assign(encoded_data.begin() + varlen_list_size,
-                                encoded_data.end());
-        }
-
-        // If RRSIGs are given, we need to extract the list of the RRSIG
-        // lengths and adjust encoded_data_ further.
-        vector<uint16_t> rrsiglen_list;
-        if (rrsig_count > 0) {
-            const size_t rrsig_len_size = rrsig_count * sizeof(uint16_t);
-            ASSERT_LE(rrsig_len_size, encoded_data.size());
-            rrsiglen_list.resize(rrsig_count * rrsig_len_size);
-            std::memcpy(&rrsiglen_list[0], &encoded_data[0], rrsig_len_size);
-            encoded_data.assign(encoded_data.begin() + rrsig_len_size,
-                                encoded_data.end());
-        }
-
-        // Create wire-format data from the encoded data
-        foreachRdataField(rrclass, rrtype, rdata_count, encoded_data,
-                          varlen_list,
-                          boost::bind(renderNameField, &renderer,
-                                      additionalRequired(rrtype), _1, _2),
-                          boost::bind(renderDataField, &renderer, _1, _2));
-
-        // 2nd dummy name
-        renderer.writeName(dummyName2());
-        // Finally, dump any RRSIGs in wire format.
-        foreachRRSig(encoded_data, rrsiglen_list,
-                     boost::bind(renderDataField, &renderer, _1, _2));
-    }
-};
-
-// Check using callbacks and calling next until the end.
-class CallbackDecoder {
-public:
-    static void decode(const isc::dns::RRClass& rrclass,
-                       const isc::dns::RRType& rrtype,
-                       size_t rdata_count, size_t sig_count, size_t,
-                       const vector<uint8_t>& encoded_data, size_t,
-                       MessageRenderer& renderer)
-    {
-        RdataReader reader(rrclass, rrtype, &encoded_data[0], rdata_count,
-                           sig_count,
-                           boost::bind(renderNameField, &renderer,
-                                       additionalRequired(rrtype), _1, _2),
-                           boost::bind(renderDataField, &renderer, _1, _2));
-        while (reader.next() != RdataReader::RRSET_BOUNDARY) {}
-        renderer.writeName(dummyName2());
-        while (reader.nextSig() != RdataReader::RRSET_BOUNDARY) {}
-    }
-};
-
-// Check using callbacks and calling iterate.
-class IterateDecoder {
-public:
-    static void decode(const isc::dns::RRClass& rrclass,
-                       const isc::dns::RRType& rrtype,
-                       size_t rdata_count, size_t sig_count, size_t,
-                       const vector<uint8_t>& encoded_data, size_t,
-                       MessageRenderer& renderer)
-    {
-        RdataReader reader(rrclass, rrtype, &encoded_data[0],
-                           rdata_count, sig_count,
-                           boost::bind(renderNameField, &renderer,
-                                       additionalRequired(rrtype), _1, _2),
-                           boost::bind(renderDataField, &renderer, _1, _2));
-        reader.iterate();
-        renderer.writeName(dummyName2());
-        reader.iterateAllSigs();
-    }
-};
-
-namespace {
-
-// Render the data to renderer, if one is set, or put it inside
-// a data buffer.
-void
-appendOrRenderData(vector<uint8_t>* where, MessageRenderer** renderer,
-                   const void* data, size_t size)
-{
-    if (*renderer != NULL) {
-        (*renderer)->writeData(data, size);
-    } else {
-        where->insert(where->end(), reinterpret_cast<const uint8_t*>(data),
-                      reinterpret_cast<const uint8_t*>(data) + size);
-    }
-}
-
-}
-
-// Similar to IterateDecoder, but it first iterates a little and rewinds
-// before actual rendering.
-class RewindAndDecode {
-private:
-    static void writeName(MessageRenderer** renderer,
-                          const LabelSequence& labels,
-                          RdataNameAttributes attributes)
-    {
-        (*renderer)->writeName(labels,
-                               (attributes & NAMEATTR_COMPRESSIBLE) != 0);
-    }
-public:
-    static void decode(const isc::dns::RRClass& rrclass,
-                       const isc::dns::RRType& rrtype,
-                       size_t rdata_count, size_t sig_count, size_t,
-                       const vector<uint8_t>& encoded_data, size_t,
-                       MessageRenderer& renderer)
-    {
-        MessageRenderer dump; // A place to dump the extra data from before
-                              // actual rendering.
-        MessageRenderer* current = &dump;
-        vector<uint8_t> placeholder; // boost::bind does not like NULL
-        RdataReader reader(rrclass, rrtype, &encoded_data[0],
-                           rdata_count, sig_count,
-                           boost::bind(writeName, &current, _1, _2),
-                           boost::bind(appendOrRenderData, &placeholder,
-                                       &current, _1, _2));
-        // Iterate a little and rewind
-        reader.next();
-        reader.nextSig();
-        reader.rewind();
-        // Do the actual rendering
-        current = &renderer;
-        reader.iterate();
-        renderer.writeName(dummyName2());
-        reader.iterateAllSigs();
-    }
-};
-
-// Decode using the iteration over one rdata each time.
-// We also count there's the correct count of Rdatas.
-class SingleIterateDecoder {
-public:
-    static void decode(const isc::dns::RRClass& rrclass,
-                       const isc::dns::RRType& rrtype,
-                       size_t rdata_count, size_t sig_count, size_t,
-                       const vector<uint8_t>& encoded_data, size_t,
-                       MessageRenderer& renderer)
-    {
-        RdataReader reader(rrclass, rrtype, &encoded_data[0],
-                           rdata_count, sig_count,
-                           boost::bind(renderNameField, &renderer,
-                                       additionalRequired(rrtype), _1, _2),
-                           boost::bind(renderDataField, &renderer, _1, _2));
-        size_t actual_count = 0;
-        while (reader.iterateRdata()) {
-            ++actual_count;
-        }
-        EXPECT_EQ(rdata_count, actual_count);
-        actual_count = 0;
-        renderer.writeName(dummyName2());
-        while (reader.iterateSingleSig()) {
-            ++actual_count;
-        }
-        EXPECT_EQ(sig_count, actual_count);
-    }
-};
-
-// This one does not adhere to the usual way the reader is used, trying
-// to confuse it. It iterates part of the data manually and then reads
-// the rest through iterate. It also reads the signatures in the middle
-// of rendering.
-template<bool start_data, bool start_sig>
-class HybridDecoder {
-public:
-    static void decode(const isc::dns::RRClass& rrclass,
-                       const isc::dns::RRType& rrtype,
-                       size_t rdata_count, size_t sig_count, size_t,
-                       const vector<uint8_t>& encoded_data,
-                       size_t encoded_data_len,
-                       MessageRenderer& renderer)
-    {
-        vector<uint8_t> data;
-        MessageRenderer* current;
-        RdataReader reader(rrclass, rrtype, &encoded_data[0],
-                           rdata_count, sig_count,
-                           boost::bind(renderNameField, &renderer,
-                                       additionalRequired(rrtype), _1, _2),
-                           boost::bind(appendOrRenderData, &data, &current, _1,
-                                       _2));
-        // The size matches
-        EXPECT_EQ(encoded_data_len, reader.getSize());
-        if (start_sig) {
-            current = NULL;
-            reader.nextSig();
-        }
-        // Render first part of data. If there's none, return empty Result and
-        // do nothing.
-        if (start_data) {
-            current = &renderer;
-            reader.next();
-        }
-        // Now, we let all sigs to be copied to data. We disable the
-        // renderer for this.
-        current = NULL;
-        reader.iterateAllSigs();
-        // Now return the renderer and render the rest of the data
-        current = &renderer;
-        reader.iterate();
-        // Now, this should not break anything and should be valid, but should
-        // return ends.
-        EXPECT_EQ(RdataReader::RRSET_BOUNDARY, reader.next());
-        EXPECT_EQ(RdataReader::RRSET_BOUNDARY, reader.nextSig());
-        // Render the name and the sigs
-        renderer.writeName(dummyName2());
-        renderer.writeData(&data[0], data.size());
-        // The size matches even after use
-        EXPECT_EQ(encoded_data_len, reader.getSize());
-    }
-};
-
-typedef ::testing::Types<ManualDecoderStyle,
-                         CallbackDecoder, IterateDecoder, SingleIterateDecoder,
-                         HybridDecoder<true, true>, HybridDecoder<true, false>,
-                         HybridDecoder<false, true>,
-                         HybridDecoder<false, false> >
-    DecoderStyles;
-// Each decoder style must contain a decode() method. Such method is expected
-// to decode the passed data, first render the Rdata into the passed renderer,
-// then write the dummyName2() there and write the RRSig data after that.
-// It may do other checks too.
-//
-// There are some slight differences to how to do the decoding, that's why we
-// have the typed test.
-TYPED_TEST_CASE(RdataEncodeDecodeTest, DecoderStyles);
-
-void
-RdataSerializationTest::encodeWrapper(size_t data_len) {
-    // make sure the data buffer is large enough for the canary
-    encoded_data_.resize(data_len + 2);
-    // set the canary data
-    encoded_data_.at(data_len) = 0xde;
-    encoded_data_.at(data_len + 1) = 0xad;
-    // encode, then check the canary is intact
-    encoder_.encode(&encoded_data_[0], data_len);
-    EXPECT_EQ(0xde, encoded_data_.at(data_len));
-    EXPECT_EQ(0xad, encoded_data_.at(data_len + 1));
-    // shrink the data buffer to the originally expected size (some tests
-    // expect that).  the actual encoded data should be intact.
-    encoded_data_.resize(data_len);
-}
-
-template<class DecoderStyle>
-void
-RdataEncodeDecodeTest<DecoderStyle>::
-checkEncode(RRClass rrclass, RRType rrtype,
-            const vector<ConstRdataPtr>& rdata_list,
-            size_t expected_varlen_fields,
-            const vector<ConstRdataPtr>& rrsig_list)
-{
-    // These two names will be rendered before and after the test RDATA,
-    // to check in case the RDATA contain a domain name whether it's
-    // compressed or not correctly.  The names in the RDATA should basically
-    // a subdomain of example.com, so it can be compressed due to dummyName2().
-    // Likewise, dummyName2() should be able to be fully compressed due to
-    // the name in the RDATA.
-    const Name dummy_name("com");
-
-    expected_renderer_.clear();
-    actual_renderer_.clear();
-    encoded_data_.clear();
-
-    // Build expected wire-format data
-    expected_renderer_.writeName(dummy_name);
-    BOOST_FOREACH(const ConstRdataPtr& rdata, rdata_list) {
-        rdata->toWire(expected_renderer_);
-    }
-    expected_renderer_.writeName(dummyName2());
-    BOOST_FOREACH(const ConstRdataPtr& rdata, rrsig_list) {
-        rdata->toWire(expected_renderer_);
-    }
-
-    // Then build wire format data using the encoded data.
-    // 1st dummy name
-    actual_renderer_.writeName(dummy_name);
-
-    // Create encoded data
-    encoder_.start(rrclass, rrtype);
-    BOOST_FOREACH(const ConstRdataPtr& rdata, rdata_list) {
-        encoder_.addRdata(*rdata);
-    }
-    BOOST_FOREACH(const ConstRdataPtr& rdata, rrsig_list) {
-        encoder_.addSIGRdata(*rdata);
-    }
-    const size_t storage_len = encoder_.getStorageLength();
-    encodeWrapper(storage_len);
-
-    DecoderStyle::decode(rrclass, rrtype, rdata_list.size(), rrsig_list.size(),
-                         expected_varlen_fields, encoded_data_, storage_len,
-                         actual_renderer_);
-
-    // Two sets of wire-format data should be identical.
-    matchWireData(expected_renderer_.getData(), expected_renderer_.getLength(),
-                  actual_renderer_.getData(), actual_renderer_.getLength());
-}
-
-template<class DecoderStyle>
-void
-RdataEncodeDecodeTest<DecoderStyle>::
-addRdataCommon(const vector<ConstRdataPtr>& rrsigs) {
-    // Basic check on the encoded data for (most of) all supported RR types,
-    // in a comprehensive manner.
-    for (size_t i = 0; test_rdata_list[i].rrclass != NULL; ++i) {
-        SCOPED_TRACE(string(test_rdata_list[i].rrclass) + "/" +
-                     test_rdata_list[i].rrtype);
-        const RRClass rrclass(test_rdata_list[i].rrclass);
-        const RRType rrtype(test_rdata_list[i].rrtype);
-        const ConstRdataPtr rdata = createRdata(rrtype, rrclass,
-                                                test_rdata_list[i].rdata);
-        rdata_list_.clear();
-        rdata_list_.push_back(rdata);
-        checkEncode(rrclass, rrtype, rdata_list_,
-                    test_rdata_list[i].n_varlen_fields, rrsigs);
-    }
-}
-
-TYPED_TEST(RdataEncodeDecodeTest, addRdata) {
-    vector<ConstRdataPtr> rrsigs;
-    this->addRdataCommon(rrsigs); // basic tests without RRSIGs (empty vector)
-
-    // Test with RRSIGs (covered type doesn't always match, but the encoder
-    // doesn't check that)
-    rrsigs.push_back(this->rrsig_rdata_);
-    this->addRdataCommon(rrsigs);
-}
-
-template<class DecoderStyle>
-void
-RdataEncodeDecodeTest<DecoderStyle>::
-addRdataMultiCommon(const vector<ConstRdataPtr>& rrsigs) {
-    // Similar to addRdata(), but test with multiple RDATAs.
-    // Four different cases are tested: a single fixed-len RDATA (A),
-    // fixed-len data + domain name (MX), variable-len data only (TXT),
-    // variable-len data + domain name (NAPTR).
-    ConstRdataPtr a_rdata2 = createRdata(RRType::A(), RRClass::IN(),
-                                         "192.0.2.54");
-    rdata_list_.clear();
-    rdata_list_.push_back(a_rdata_);
-    rdata_list_.push_back(a_rdata2);
-    checkEncode(RRClass::IN(), RRType::A(), rdata_list_, 0, rrsigs);
-
-    ConstRdataPtr mx_rdata1 = createRdata(RRType::MX(), RRClass::IN(),
-                                          "5 mx1.example.com");
-    ConstRdataPtr mx_rdata2 = createRdata(RRType::MX(), RRClass::IN(),
-                                          "10 mx2.example.com");
-    rdata_list_.clear();
-    rdata_list_.push_back(mx_rdata1);
-    rdata_list_.push_back(mx_rdata2);
-    checkEncode(RRClass::IN(), RRType::MX(), rdata_list_, 0, rrsigs);
-
-    ConstRdataPtr txt_rdata1 = createRdata(RRType::TXT(), RRClass::IN(),
-                                           "foo bar baz");
-    ConstRdataPtr txt_rdata2 = createRdata(RRType::TXT(), RRClass::IN(),
-                                          "another text data");
-    rdata_list_.clear();
-    rdata_list_.push_back(txt_rdata1);
-    rdata_list_.push_back(txt_rdata2);
-    checkEncode(RRClass::IN(), RRType::TXT(), rdata_list_, 1, rrsigs);
-
-    ConstRdataPtr naptr_rdata1 =
-        createRdata(RRType::NAPTR(), RRClass::IN(),
-                    "100 50 \"s\" \"http\" \"\" _http._tcp.example.com");
-    ConstRdataPtr naptr_rdata2 =
-        createRdata(RRType::NAPTR(), RRClass::IN(),
-                    "200 100 \"s\" \"http\" \"\" _http._tcp.example.com");
-    rdata_list_.clear();
-    rdata_list_.push_back(naptr_rdata1);
-    rdata_list_.push_back(naptr_rdata2);
-    checkEncode(RRClass::IN(), RRType::NAPTR(), rdata_list_, 1, rrsigs);
-}
-
-void ignoreName(const LabelSequence&, unsigned) {
-}
-
-void
-checkLargeData(const in::DHCID* decoded, bool* called, const void* encoded,
-               size_t length)
-{
-    EXPECT_FALSE(*called); // Called exactly once
-    *called = true;
-
-    // Reconstruct the Rdata and check it.
-    isc::util::InputBuffer ib(encoded, length);
-    const in::DHCID reconstructed(ib, ib.getLength());
-    EXPECT_EQ(0, reconstructed.compare(*decoded));
-}
-
-TEST_F(RdataSerializationTest, encodeLargeRdata) {
-    // There should be no reason for a large RDATA to fail in encoding,
-    // but we check such a case explicitly.
-
-    encoded_data_.resize(65535); // max unsigned 16-bit int
-    isc::util::InputBuffer buffer(&encoded_data_[0], encoded_data_.size());
-    const in::DHCID large_dhcid(buffer, encoded_data_.size());
-
-    encoder_.start(RRClass::IN(), RRType::DHCID());
-    encoder_.addRdata(large_dhcid);
-    encodeWrapper(encoder_.getStorageLength());
-
-    // The encoded data should be identical to the original one.
-    bool called = false;
-    RdataReader reader(RRClass::IN(), RRType::DHCID(), &encoded_data_[0], 1, 0,
-                       ignoreName, boost::bind(checkLargeData, &large_dhcid,
-                                               &called, _1, _2));
-    reader.iterate();
-    EXPECT_TRUE(called);
-    called = false;
-    reader.iterateAllSigs();
-    EXPECT_FALSE(called);
-}
-
-TYPED_TEST(RdataEncodeDecodeTest, addRdataMulti) {
-    vector<ConstRdataPtr> rrsigs;
-    this->addRdataMultiCommon(rrsigs); // test without RRSIGs (empty vector)
-
-    // Tests with two RRSIGs
-    rrsigs.push_back(this->rrsig_rdata_);
-    rrsigs.push_back(createRdata(RRType::RRSIG(), RRClass::IN(),
-                                 "A 5 2 3600 20120814220826 "
-                                 "20120715220826 54321 com. FAKE"));
-    this->addRdataMultiCommon(rrsigs);
-}
-
-TEST_F(RdataSerializationTest, badAddRdata) {
-    // Some operations must follow start().
-    EXPECT_THROW(encoder_.addRdata(*a_rdata_), isc::InvalidOperation);
-    EXPECT_THROW(encoder_.getStorageLength(), isc::InvalidOperation);
-    // will allocate space of some arbitrary size (256 bytes)
-    EXPECT_THROW(encodeWrapper(256), isc::InvalidOperation);
-
-    // Bad buffer for encode
-    encoder_.start(RRClass::IN(), RRType::A());
-    encoder_.addRdata(*a_rdata_);
-    const size_t buf_len = encoder_.getStorageLength();
-    // NULL buffer for encode
-    EXPECT_THROW(encoder_.encode(NULL, buf_len), isc::BadValue);
-    // buffer length is too short (we don't use the wrraper because we don't
-    // like to tweak the length arg to encode()).
-    encoded_data_.resize(buf_len - 1);
-    EXPECT_THROW(encoder_.encode(&encoded_data_[0], buf_len - 1),
-                 isc::BadValue);
-
-    // Type of RDATA and the specified RR type don't match.  addRdata() should
-    // detect this inconsistency.
-    encoder_.start(RRClass::IN(), RRType::AAAA());
-    EXPECT_THROW(encoder_.addRdata(*a_rdata_), isc::BadValue);
-
-    // Likewise.
-    encoder_.start(RRClass::IN(), RRType::A());
-    EXPECT_THROW(encoder_.addRdata(*aaaa_rdata_), isc::BadValue);
-
-    // Likewise.  The encoder expects the first name completes the data, and
-    // throws on the second due as an unexpected name field.
-    const ConstRdataPtr rp_rdata =
-        createRdata(RRType::RP(), RRClass::IN(), "a.example. b.example");
-    encoder_.start(RRClass::IN(), RRType::NS());
-    EXPECT_THROW(encoder_.addRdata(*rp_rdata), isc::BadValue);
-
-    // Likewise.  The encoder considers the name data a variable length data
-    // field, and throws on the first name.
-    encoder_.start(RRClass::IN(), RRType::DHCID());
-    EXPECT_THROW(encoder_.addRdata(*rp_rdata), isc::BadValue);
-
-    // Likewise.  The text RDATA (2 bytes) will be treated as MX preference,
-    // and the encoder will still expect to see a domain name.
-    const ConstRdataPtr txt_rdata = createRdata(RRType::TXT(), RRClass::IN(),
-                                                "a");
-    encoder_.start(RRClass::IN(), RRType::MX());
-    EXPECT_THROW(encoder_.addRdata(*txt_rdata), isc::BadValue);
-
-    // Similar to the previous one, but in this case there's no data field
-    // in the spec.
-    encoder_.start(RRClass::IN(), RRType::NS());
-    EXPECT_THROW(encoder_.addRdata(*txt_rdata), isc::BadValue);
-
-    // Likewise.  Inconsistent name compression policy.
-    const ConstRdataPtr ns_rdata =
-        createRdata(RRType::NS(), RRClass::IN(), "ns.example");
-    encoder_.start(RRClass::IN(), RRType::DNAME());
-    EXPECT_THROW(encoder_.addRdata(*ns_rdata), isc::BadValue);
-
-    // Same as the previous one, opposite inconsistency.
-    const ConstRdataPtr dname_rdata =
-        createRdata(RRType::DNAME(), RRClass::IN(), "dname.example");
-    encoder_.start(RRClass::IN(), RRType::NS());
-    EXPECT_THROW(encoder_.addRdata(*dname_rdata), isc::BadValue);
-
-    // RDATA len exceeds the 16-bit range.  Technically not invalid, but
-    // we don't support that (and it's practically useless anyway).
-    encoded_data_.resize(65536); // use encoded_data_ for placeholder
-    isc::util::InputBuffer buffer(&encoded_data_[0], encoded_data_.size());
-    encoder_.start(RRClass::IN(), RRType::DHCID());
-    EXPECT_THROW(encoder_.addRdata(in::DHCID(buffer, encoded_data_.size())),
-                                   RdataEncodingError);
-
-    // RRSIG cannot be used as the main RDATA type (can only be added as
-    // a signature for some other type of RDATAs).
-    EXPECT_THROW(encoder_.start(RRClass::IN(), RRType::RRSIG()),
-                 isc::BadValue);
-}
-
-void
-checkSigData(const ConstRdataPtr& decoded, bool* called, const void* encoded,
-             size_t length)
-{
-    EXPECT_FALSE(*called); // Called exactly once
-    *called = true;
-
-    // Reconstruct the RRSig and check it.
-    isc::util::InputBuffer ib(encoded, length);
-    const generic::RRSIG reconstructed(ib, ib.getLength());
-    EXPECT_EQ(0, reconstructed.compare(*decoded));
-}
-
-TEST_F(RdataSerializationTest, addSIGRdataOnly) {
-    // Encoded data that only contain RRSIGs.  Mostly useless, but can happen
-    // (in a partially broken zone) and it's accepted.
-    encoder_.start(RRClass::IN(), RRType::A());
-    encoder_.addSIGRdata(*rrsig_rdata_);
-    encodeWrapper(encoder_.getStorageLength());
-    ASSERT_LT(sizeof(uint16_t), encoder_.getStorageLength());
-
-    bool called = false;
-    RdataReader reader(RRClass::IN(), RRType::A(), &encoded_data_[0], 0, 1,
-                       ignoreName, boost::bind(checkSigData, rrsig_rdata_,
-                                               &called, _1, _2));
-    reader.iterate();
-    EXPECT_FALSE(called);
-    reader.iterateAllSigs();
-    EXPECT_TRUE(called);
-}
-
-TEST_F(RdataSerializationTest, badAddSIGRdata) {
-    // try adding SIG before start
-    EXPECT_THROW(encoder_.addSIGRdata(*rrsig_rdata_), isc::InvalidOperation);
-
-    // Very big RRSIG.  This implementation rejects it.
-    isc::util::OutputBuffer ob(0);
-    rrsig_rdata_->toWire(ob);
-    // append dummy trailing signature to make it too big
-    vector<uint8_t> dummy_sig(65536 - ob.getLength());
-    ob.writeData(&dummy_sig[0], dummy_sig.size());
-    ASSERT_EQ(65536, ob.getLength());
-
-    isc::util::InputBuffer ib(ob.getData(), ob.getLength());
-    const generic::RRSIG big_sigrdata(ib, ob.getLength());
-    encoder_.start(RRClass::IN(), RRType::A());
-    EXPECT_THROW(encoder_.addSIGRdata(big_sigrdata), RdataEncodingError);
-}
-}
diff --git a/src/lib/datasrc/memory/tests/rdataset_unittest.cc b/src/lib/datasrc/memory/tests/rdataset_unittest.cc
deleted file mode 100644
index 897e53c..0000000
--- a/src/lib/datasrc/memory/tests/rdataset_unittest.cc
+++ /dev/null
@@ -1,298 +0,0 @@
-// 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 <exceptions/exceptions.h>
-
-#include <util/buffer.h>
-#include <util/memory_segment_local.h>
-
-#include <dns/rdata.h>
-#include <dns/rdataclass.h>
-#include <dns/rrset.h>
-#include <dns/rrclass.h>
-#include <dns/rrtype.h>
-#include <dns/rrttl.h>
-
-#include <datasrc/memory/rdata_serialization.h>
-#include <datasrc/memory/rdataset.h>
-
-#include <testutils/dnsmessage_test.h>
-
-#include <gtest/gtest.h>
-
-#include <boost/lexical_cast.hpp>
-
-#include <string>
-
-using namespace isc::dns;
-using namespace isc::dns::rdata;
-using namespace isc::datasrc::memory;
-using namespace isc::testutils;
-using boost::lexical_cast;
-
-namespace {
-
-class RdataSetTest : public ::testing::Test {
-protected:
-    RdataSetTest() :
-        // 1076895760 = 0x40302010.  Use this so we fill in all 8-bit "field"
-        // of the 32-bit TTL
-        a_rrset_(textToRRset("www.example.com. 1076895760 IN A 192.0.2.1")),
-        rrsig_rrset_(textToRRset("www.example.com. 1076895760 IN RRSIG "
-                                 "A 5 2 3600 20120814220826 20120715220826 "
-                                 "1234 example.com. FAKE"))
-    {}
-    void TearDown() {
-        EXPECT_TRUE(mem_sgmt_.allMemoryDeallocated());
-    }
-
-    ConstRRsetPtr a_rrset_, rrsig_rrset_;
-    isc::util::MemorySegmentLocal mem_sgmt_;
-    RdataEncoder encoder_;
-};
-
-// Convert the given 32-bit integer (network byte order) to the corresponding
-// RRTTL object.
-RRTTL
-restoreTTL(const void* ttl_data) {
-    isc::util::InputBuffer b(ttl_data, sizeof(uint32_t));
-    return (RRTTL(b));
-}
-
-// A helper callback for checkRdataSet.  This confirms the given data
-// is the expected in::A RDATA (the value is taken from the RdataSetTest
-// constructor).
-void
-checkData(const void* data, size_t size) {
-    isc::util::InputBuffer b(data, size);
-    EXPECT_EQ(0, in::A(b, size).compare(in::A("192.0.2.1")));
-}
-
-// This is a set of checks for an RdataSet created with some simple
-// conditions.  with_rrset/with_rrsig is true iff the RdataSet is supposed to
-// contain normal/RRSIG RDATA.
-void
-checkRdataSet(const RdataSet& rdataset, bool with_rrset, bool with_rrsig) {
-    EXPECT_FALSE(rdataset.next); // by default the next pointer should be NULL
-    EXPECT_EQ(RRType::A(), rdataset.type);
-    // See the RdataSetTest constructor for the magic number.
-    EXPECT_EQ(RRTTL(1076895760), restoreTTL(rdataset.getTTLData()));
-    EXPECT_EQ(with_rrset ? 1 : 0, rdataset.getRdataCount());
-    EXPECT_EQ(with_rrsig ? 1 : 0, rdataset.getSigRdataCount());
-
-    // A simple test for the data content.  Details tests for the encoder/
-    // reader should be basically sufficient for various cases of the data,
-    // and the fact that this test doesn't detect memory leak should be
-    // reasonably sufficient that the implementation handles the data region
-    // correctly.  Here we check one simple case for a simple form of RDATA,
-    // mainly for checking the behavior of getDataBuf().
-    RdataReader reader(RRClass::IN(), RRType::A(),
-                       reinterpret_cast<const uint8_t*>(
-                           rdataset.getDataBuf()),
-                       rdataset.getRdataCount(), rdataset.getSigRdataCount(),
-                       &RdataReader::emptyNameAction, checkData);
-    reader.iterate();
-}
-
-TEST_F(RdataSetTest, create) {
-    // A simple case of creating an RdataSet.  Confirming the resulting
-    // fields have the expected values, and then destroying it (TearDown()
-    // would detect any memory leak)
-    RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
-                                          ConstRRsetPtr());
-    checkRdataSet(*rdataset, true, false);
-    RdataSet::destroy(mem_sgmt_, RRClass::IN(), rdataset);
-}
-
-TEST_F(RdataSetTest, getNext) {
-    RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
-                                          ConstRRsetPtr());
-
-    // By default, the next pointer should be NULL (already tested in other
-    // test cases), which should be the case with getNext().  We test both
-    // mutable and immutable versions of getNext().
-    EXPECT_EQ(static_cast<RdataSet*>(NULL), rdataset->getNext());
-    EXPECT_EQ(static_cast<const RdataSet*>(NULL),
-              static_cast<const RdataSet*>(rdataset)->getNext());
-
-    // making a link (it would form an infinite loop, but it doesn't matter
-    // in this test), and check the pointer returned by getNext().
-    rdataset->next = rdataset;
-    EXPECT_EQ(rdataset, static_cast<const RdataSet*>(rdataset)->getNext());
-
-    RdataSet::destroy(mem_sgmt_, RRClass::IN(), rdataset);
-}
-
-// A helper function to create an RRset containing the given number of
-// unique RDATAs.
-ConstRRsetPtr
-getRRsetWithRdataCount(size_t rdata_count) {
-    RRsetPtr rrset(new RRset(Name("example.com"), RRClass::IN(), RRType::TXT(),
-                             RRTTL(3600)));
-    for (size_t i = 0; i < rdata_count; ++i) {
-        rrset->addRdata(rdata::createRdata(RRType::TXT(), RRClass::IN(),
-                                           lexical_cast<std::string>(i)));
-    }
-    return (rrset);
-}
-
-TEST_F(RdataSetTest, createManyRRs) {
-    // RRset with possible maximum number of RDATAs
-    RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder_,
-                                          getRRsetWithRdataCount(8191),
-                                          ConstRRsetPtr());
-    EXPECT_EQ(8191, rdataset->getRdataCount());
-    EXPECT_EQ(0, rdataset->getSigRdataCount());
-    RdataSet::destroy(mem_sgmt_, RRClass::IN(), rdataset);
-
-    // Exceeding that will result in an exception.
-    EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_,
-                                  getRRsetWithRdataCount(8192),
-                                  ConstRRsetPtr()),
-                 RdataSetError);
-    // To be very sure even try larger number than the threshold
-    EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_,
-                                  getRRsetWithRdataCount(65535),
-                                  ConstRRsetPtr()),
-                 RdataSetError);
-}
-
-TEST_F(RdataSetTest, createWithRRSIG) {
-    // Normal case.
-    RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
-                                          rrsig_rrset_);
-    checkRdataSet(*rdataset, true, true);
-    RdataSet::destroy(mem_sgmt_, RRClass::IN(), rdataset);
-
-    // Unusual case: TTL doesn't match.  This implementation accepts that,
-    // using the TTL of the covered RRset.
-    ConstRRsetPtr rrsig_badttl(textToRRset(
-                                   "www.example.com. 3600 IN RRSIG "
-                                   "A 5 2 3600 20120814220826 "
-                                   "20120715220826 1234 example.com. FAKE"));
-    rdataset = RdataSet::create(mem_sgmt_, encoder_, a_rrset_, rrsig_badttl);
-    checkRdataSet(*rdataset, true, true);
-    RdataSet::destroy(mem_sgmt_, RRClass::IN(), rdataset);
-}
-
-// A helper function to create an RRSIG RRset containing the given number of
-// unique RDATAs.
-ConstRRsetPtr
-getRRSIGWithRdataCount(size_t sig_count) {
-    RRsetPtr rrset(new RRset(Name("example.com"), RRClass::IN(),
-                             RRType::RRSIG(), RRTTL(3600)));
-    // We use a base wire-format image and tweak the original TTL field to
-    // generate unique RDATAs in the loop.  (Creating them from corresponding
-    // text is simpler, but doing so for a large number of RRSIGs is
-    // relatively heavy and could be too long for unittests).
-    ConstRdataPtr rrsig_base =
-        rdata::createRdata(RRType::RRSIG(), RRClass::IN(),
-                           "A 5 2 3600 20120814220826 20120715220826 1234 "
-                           "example.com. FAKE");
-    isc::util::OutputBuffer ob(0);
-    rrsig_base->toWire(ob);
-    for (size_t i = 0; i < sig_count; ++i) {
-        ob.writeUint16At((i >> 16) & 0xffff, 4);
-        ob.writeUint16At(i & 0xffff, 6);
-        isc::util::InputBuffer ib(ob.getData(), ob.getLength());
-        rrset->addRdata(rdata::createRdata(RRType::RRSIG(), RRClass::IN(),
-                                           ib, ib.getLength()));
-    }
-    return (rrset);
-}
-
-TEST_F(RdataSetTest, createManyRRSIGs) {
-    // 7 has a special meaning in the implementation: if the number of the
-    // RRSIGs reaches this value, an extra 'sig count' field will be created.
-    RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
-                                          getRRSIGWithRdataCount(7));
-    EXPECT_EQ(7, rdataset->getSigRdataCount());
-    RdataSet::destroy(mem_sgmt_, RRClass::IN(), rdataset);
-
-    // 8 would cause overflow in the normal 3-bit field if there were no extra
-    // count field.
-    rdataset = RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
-                                getRRSIGWithRdataCount(8));
-    EXPECT_EQ(8, rdataset->getSigRdataCount());
-    RdataSet::destroy(mem_sgmt_, RRClass::IN(), rdataset);
-
-    // Up to 2^16-1 RRSIGs are allowed (although that would be useless
-    // in practice)
-    rdataset = RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
-                                getRRSIGWithRdataCount(65535));
-    EXPECT_EQ(65535, rdataset->getSigRdataCount());
-    RdataSet::destroy(mem_sgmt_, RRClass::IN(), rdataset);
-
-    // Exceeding this limit will result in an exception.
-    EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
-                                  getRRSIGWithRdataCount(65536)),
-                 RdataSetError);
-    // To be very sure even try larger number than the threshold
-    EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
-                                  getRRSIGWithRdataCount(70000)),
-                 RdataSetError);
-}
-
-TEST_F(RdataSetTest, createWithRRSIGOnly) {
-    // A rare, but allowed, case: RdataSet without the main RRset but with
-    // RRSIG.
-    RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder_, ConstRRsetPtr(),
-                                          rrsig_rrset_);
-    checkRdataSet(*rdataset, false, true);
-    RdataSet::destroy(mem_sgmt_, RRClass::IN(), rdataset);
-}
-
-TEST_F(RdataSetTest, badCeate) {
-    // Neither the RRset nor RRSIG RRset is given
-    EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_, ConstRRsetPtr(),
-                                  ConstRRsetPtr()), isc::BadValue);
-
-    // Empty RRset (An RRset without RDATA)
-    ConstRRsetPtr empty_rrset(new RRset(Name("example.com"), RRClass::IN(),
-                                        RRType::A(), RRTTL(3600)));
-    EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_, empty_rrset,
-                                  ConstRRsetPtr()), isc::BadValue);
-    ConstRRsetPtr empty_rrsig(new RRset(Name("example.com"), RRClass::IN(),
-                                        RRType::RRSIG(), RRTTL(3600)));
-    EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_, ConstRRsetPtr(),
-                                  empty_rrsig), isc::BadValue);
-
-    // The RRset type and RRSIG's type covered don't match
-    ConstRRsetPtr bad_rrsig(textToRRset(
-                                "www.example.com. 1076895760 IN RRSIG "
-                                "NS 5 2 3600 20120814220826 20120715220826 "
-                                "1234 example.com. FAKE"));
-    EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_, a_rrset_, bad_rrsig),
-                 isc::BadValue);
-
-    // Pass non RRSIG for the sig parameter
-    EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_, a_rrset_, a_rrset_),
-                 isc::BadValue);
-
-    // Pass RRSIG for normal RRset (the RdataEncoder will catch this and throw)
-    EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_, rrsig_rrset_,
-                                  rrsig_rrset_),
-                 isc::BadValue);
-
-    // RR class doesn't match between RRset and RRSIG
-    ConstRRsetPtr badclass_rrsig(textToRRset(
-                                     "www.example.com. 1076895760 CH RRSIG "
-                                     "A 5 2 3600 20120814220826 "
-                                     "20120715220826 1234 example.com. FAKE",
-                                     RRClass::CH()));
-    EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
-                                  badclass_rrsig),
-                 isc::BadValue);
-}
-}
diff --git a/src/lib/datasrc/memory/tests/run_unittests.cc b/src/lib/datasrc/memory/tests/run_unittests.cc
deleted file mode 100644
index 6321976..0000000
--- a/src/lib/datasrc/memory/tests/run_unittests.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-// 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 <gtest/gtest.h>
-#include <util/unittests/run_all.h>
-#include <log/logger_support.h>
-
-int
-main(int argc, char* argv[]) {
-    ::testing::InitGoogleTest(&argc, argv);
-
-    isc::log::initLogger();
-
-    return (isc::util::unittests::run_all());
-}
diff --git a/src/lib/datasrc/memory/tests/segment_object_holder_unittest.cc b/src/lib/datasrc/memory/tests/segment_object_holder_unittest.cc
deleted file mode 100644
index d27e364..0000000
--- a/src/lib/datasrc/memory/tests/segment_object_holder_unittest.cc
+++ /dev/null
@@ -1,67 +0,0 @@
-// 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 <util/memory_segment_local.h>
-
-#include <datasrc/memory/segment_object_holder.h>
-
-#include <gtest/gtest.h>
-
-using namespace isc::util;
-using namespace isc::datasrc::memory;
-using namespace isc::datasrc::memory::detail;
-
-namespace {
-const int TEST_ARG_VAL = 42;    // arbitrary chosen magic number
-
-class TestObject {
-public:
-    static void destroy(MemorySegment& sgmt, TestObject* obj, int arg) {
-        sgmt.deallocate(obj, sizeof(*obj));
-        EXPECT_EQ(TEST_ARG_VAL, arg);
-    }
-};
-
-void
-useHolder(MemorySegment& sgmt, TestObject* obj, bool release) {
-    // Create a holder object, check the return value of get(), and,
-    // if requested, release the held object.  At the end of function
-    // the holder is destructed, and if the object hasn't been released by
-    // then, it should be deallocated.  Passed argument is checked in its
-    // deallocate().
-
-    typedef SegmentObjectHolder<TestObject, int> HolderType;
-    HolderType holder(sgmt, obj, TEST_ARG_VAL);
-    EXPECT_EQ(obj, holder.get());
-    if (release) {
-        EXPECT_EQ(obj, holder.release());
-    }
-}
-
-TEST(SegmentObjectHolderTest, foo) {
-    MemorySegmentLocal sgmt;
-    void* p = sgmt.allocate(sizeof(TestObject));
-    TestObject* obj = new(p) TestObject;
-
-    // Use holder, and release the content.  The memory shouldn't be
-    // deallocated.
-    useHolder(sgmt, obj, true);
-    EXPECT_FALSE(sgmt.allMemoryDeallocated());
-
-    // Use holder, and let it deallocate the object.  The memory segment
-    // should now be empty.
-    useHolder(sgmt, obj, false);
-    EXPECT_TRUE(sgmt.allMemoryDeallocated());
-}
-}
diff --git a/src/lib/datasrc/memory/tests/testdata/Makefile.am b/src/lib/datasrc/memory/tests/testdata/Makefile.am
deleted file mode 100644
index 2d92266..0000000
--- a/src/lib/datasrc/memory/tests/testdata/Makefile.am
+++ /dev/null
@@ -1,30 +0,0 @@
-CLEANFILES = *.copied
-
-EXTRA_DIST =  empty.zone
-EXTRA_DIST += example.org.zone
-EXTRA_DIST += example.org-empty.zone
-
-EXTRA_DIST += example.org-broken1.zone
-EXTRA_DIST += example.org-broken2.zone
-EXTRA_DIST += example.org-cname-and-not-nsec-1.zone
-EXTRA_DIST += example.org-cname-and-not-nsec-2.zone
-EXTRA_DIST += example.org-dname-ns-apex-1.zone
-EXTRA_DIST += example.org-dname-ns-apex-2.zone
-EXTRA_DIST += example.org-dname-ns-nonapex-1.zone
-EXTRA_DIST += example.org-dname-ns-nonapex-2.zone
-EXTRA_DIST += example.org-duplicate-type-bad.zone
-EXTRA_DIST += example.org-duplicate-type.zone
-EXTRA_DIST += example.org-multiple-cname.zone
-EXTRA_DIST += example.org-multiple-dname.zone
-EXTRA_DIST += example.org-multiple-nsec3.zone
-EXTRA_DIST += example.org-multiple-nsec3param.zone
-EXTRA_DIST += example.org-multiple.zone
-EXTRA_DIST += example.org-nsec3-fewer-labels.zone example.org-nsec3-more-labels.zone
-EXTRA_DIST += example.org-nsec3-signed-no-param.zone
-EXTRA_DIST += example.org-nsec3-signed.zone
-EXTRA_DIST += example.org-out-of-zone.zone
-EXTRA_DIST += example.org-rrsig-follows-nothing.zone
-EXTRA_DIST += example.org-rrsigs.zone
-EXTRA_DIST += example.org-wildcard-dname.zone
-EXTRA_DIST += example.org-wildcard-ns.zone
-EXTRA_DIST += example.org-wildcard-nsec3.zone
diff --git a/src/lib/datasrc/memory/tests/testdata/empty.zone b/src/lib/datasrc/memory/tests/testdata/empty.zone
deleted file mode 100644
index e69de29..0000000
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-broken1.zone b/src/lib/datasrc/memory/tests/testdata/example.org-broken1.zone
deleted file mode 100644
index 317095d..0000000
--- a/src/lib/datasrc/memory/tests/testdata/example.org-broken1.zone
+++ /dev/null
@@ -1 +0,0 @@
-This is a broken zone that should not parse.
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-broken2.zone b/src/lib/datasrc/memory/tests/testdata/example.org-broken2.zone
deleted file mode 100644
index 2f9fd98..0000000
--- a/src/lib/datasrc/memory/tests/testdata/example.org-broken2.zone
+++ /dev/null
@@ -1,5 +0,0 @@
-;; broken example.org zone, where some RRs are OK, but others aren't
-example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 73 3600 300 3600000 3600
-ns1.example.org.		      3600 IN A		192.0.2.1
-ns2.example.org.		      3600 IN A		192.0.2.2
-ns2.a.example.com.		      3600 IN AAAA
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-cname-and-not-nsec-1.zone b/src/lib/datasrc/memory/tests/testdata/example.org-cname-and-not-nsec-1.zone
deleted file mode 100644
index 5533663..0000000
--- a/src/lib/datasrc/memory/tests/testdata/example.org-cname-and-not-nsec-1.zone
+++ /dev/null
@@ -1,4 +0,0 @@
-;; CNAME + other is an error
-example.org.				      86400 IN SOA	ns.example.org. ns.example.org. 2012091009 7200 3600 2592000 1200
-a.example.org.				      7200  IN A	192.168.0.1
-a.example.org.				      3600  IN CNAME	foo.example.com.
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-cname-and-not-nsec-2.zone b/src/lib/datasrc/memory/tests/testdata/example.org-cname-and-not-nsec-2.zone
deleted file mode 100644
index 966aeeb..0000000
--- a/src/lib/datasrc/memory/tests/testdata/example.org-cname-and-not-nsec-2.zone
+++ /dev/null
@@ -1,4 +0,0 @@
-;; CNAME + other is an error
-example.org.				      86400 IN SOA	ns.example.org. ns.example.org. 2012091007 7200 3600 2592000 1200
-a.example.org.				      3600  IN CNAME	foo.example.com.
-a.example.org.				      7200  IN A	192.168.0.1
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-dname-ns-apex-1.zone b/src/lib/datasrc/memory/tests/testdata/example.org-dname-ns-apex-1.zone
deleted file mode 100644
index f57c25d..0000000
--- a/src/lib/datasrc/memory/tests/testdata/example.org-dname-ns-apex-1.zone
+++ /dev/null
@@ -1,4 +0,0 @@
-;; DNAME + NS (apex)
-example.org.				      86400 IN SOA	ns.example.org. ns.example.org. 2012091015 7200 3600 2592000 1200
-example.org.				      3600  IN DNAME	foo.example.com.
-example.org.				      3600  IN NS	bar.example.com.
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-dname-ns-apex-2.zone b/src/lib/datasrc/memory/tests/testdata/example.org-dname-ns-apex-2.zone
deleted file mode 100644
index bb3f191..0000000
--- a/src/lib/datasrc/memory/tests/testdata/example.org-dname-ns-apex-2.zone
+++ /dev/null
@@ -1,4 +0,0 @@
-;; DNAME + NS (apex)
-example.org.				      86400 IN SOA	ns.example.org. ns.example.org. 2012091016 7200 3600 2592000 1200
-example.org.				      3600  IN NS	bar.example.com.
-example.org.				      3600  IN DNAME	foo.example.com.
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-dname-ns-nonapex-1.zone b/src/lib/datasrc/memory/tests/testdata/example.org-dname-ns-nonapex-1.zone
deleted file mode 100644
index 68a9805..0000000
--- a/src/lib/datasrc/memory/tests/testdata/example.org-dname-ns-nonapex-1.zone
+++ /dev/null
@@ -1,4 +0,0 @@
-;; DNAME + NS (non-apex)
-example.org.				      86400 IN SOA	ns.example.org. ns.example.org. 2012091014 7200 3600 2592000 1200
-ns1.example.org.			      3600  IN DNAME	foo.example.com.
-ns1.example.org.			      3600  IN NS	bar.example.com.
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-dname-ns-nonapex-2.zone b/src/lib/datasrc/memory/tests/testdata/example.org-dname-ns-nonapex-2.zone
deleted file mode 100644
index 1b671dd..0000000
--- a/src/lib/datasrc/memory/tests/testdata/example.org-dname-ns-nonapex-2.zone
+++ /dev/null
@@ -1,4 +0,0 @@
-;; DNAME + NS (non-apex)
-example.org.				      86400 IN SOA	ns.example.org. ns.example.org. 2012091015 7200 3600 2592000 1200
-ns1.example.org.			      3600  IN NS	bar.example.com.
-ns1.example.org.			      3600  IN DNAME	foo.example.com.
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-duplicate-type-bad.zone b/src/lib/datasrc/memory/tests/testdata/example.org-duplicate-type-bad.zone
deleted file mode 100644
index 06c7dff..0000000
--- a/src/lib/datasrc/memory/tests/testdata/example.org-duplicate-type-bad.zone
+++ /dev/null
@@ -1,4 +0,0 @@
-example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 77 3600 300 3600000 3600
-ns1.example.org.		      3600 IN A	 	192.168.0.1
-ns1.example.org.		      3600 IN AAAA 	::1
-ns1.example.org.		      3600 IN A	 	192.168.0.2
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-duplicate-type.zone b/src/lib/datasrc/memory/tests/testdata/example.org-duplicate-type.zone
deleted file mode 100644
index 6e5c1b8..0000000
--- a/src/lib/datasrc/memory/tests/testdata/example.org-duplicate-type.zone
+++ /dev/null
@@ -1,4 +0,0 @@
-example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 76 3600 300 3600000 3600
-ns1.example.org.		      3600 IN A	 	192.168.0.1
-ns1.example.org.		      3600 IN A	 	192.168.0.2
-ns1.example.org.		      3600 IN AAAA 	::1
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-empty.zone b/src/lib/datasrc/memory/tests/testdata/example.org-empty.zone
deleted file mode 100644
index f11b9b8..0000000
--- a/src/lib/datasrc/memory/tests/testdata/example.org-empty.zone
+++ /dev/null
@@ -1,2 +0,0 @@
-;; empty example.org zone
-example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 68 3600 300 3600000 3600
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-multiple-cname.zone b/src/lib/datasrc/memory/tests/testdata/example.org-multiple-cname.zone
deleted file mode 100644
index 0a0c983..0000000
--- a/src/lib/datasrc/memory/tests/testdata/example.org-multiple-cname.zone
+++ /dev/null
@@ -1,3 +0,0 @@
-example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 78 3600 300 3600000 3600
-ns1.example.org.		      3600 IN CNAME	foo.example.com.
-ns1.example.org.		      3600 IN CNAME	bar.example.com.
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-multiple-dname.zone b/src/lib/datasrc/memory/tests/testdata/example.org-multiple-dname.zone
deleted file mode 100644
index 3d581d0..0000000
--- a/src/lib/datasrc/memory/tests/testdata/example.org-multiple-dname.zone
+++ /dev/null
@@ -1,3 +0,0 @@
-example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 79 3600 300 3600000 3600
-ns1.example.org.		      3600 IN DNAME	foo.example.com.
-ns1.example.org.		      3600 IN DNAME	bar.example.com.
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-multiple-nsec3.zone b/src/lib/datasrc/memory/tests/testdata/example.org-multiple-nsec3.zone
deleted file mode 100644
index 874023a..0000000
--- a/src/lib/datasrc/memory/tests/testdata/example.org-multiple-nsec3.zone
+++ /dev/null
@@ -1,3 +0,0 @@
-example.org.				      86400 IN SOA	ns.example.org. ns.example.org. 2012090702 7200 3600 2592000 1200
-09GM5T42SMIMT7R8DF6RTG80SFMS1NLU.example.org. 1200 IN NSEC3	1 0 10 AABBCCDD RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD A RRSIG
-09GM5T42SMIMT7R8DF6RTG80SFMS1NLU.example.org. 1200 IN NSEC3	1 0 10 AABBCCDD 09GM5T42SMIMT7R8DF6RTG80SFMS1NLU NS SOA RRSIG DNSKEY NSEC3PARAM
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-multiple-nsec3param.zone b/src/lib/datasrc/memory/tests/testdata/example.org-multiple-nsec3param.zone
deleted file mode 100644
index 5e69518..0000000
--- a/src/lib/datasrc/memory/tests/testdata/example.org-multiple-nsec3param.zone
+++ /dev/null
@@ -1,3 +0,0 @@
-example.org.				      86400 IN SOA	ns.example.org. ns.example.org. 2012090700 7200 3600 2592000 1200
-example.org.				      0	IN NSEC3PARAM	1 0 10 AABBCCDD
-example.org.				      0	IN NSEC3PARAM	1 0 10 AABBCCDD
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-multiple.zone b/src/lib/datasrc/memory/tests/testdata/example.org-multiple.zone
deleted file mode 100644
index f473ae6..0000000
--- a/src/lib/datasrc/memory/tests/testdata/example.org-multiple.zone
+++ /dev/null
@@ -1,4 +0,0 @@
-;; Multiple RDATA for testing separate RRs iterator
-example.org.  		   	 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 78 3600 300 3600000 3600
-a.example.org.		   	 3600 IN A	192.168.0.1
-a.example.org.		   	 3600 IN A	192.168.0.2
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-nsec3-fewer-labels.zone b/src/lib/datasrc/memory/tests/testdata/example.org-nsec3-fewer-labels.zone
deleted file mode 100644
index 0221269..0000000
--- a/src/lib/datasrc/memory/tests/testdata/example.org-nsec3-fewer-labels.zone
+++ /dev/null
@@ -1,3 +0,0 @@
-;; NSEC3 names with labels != (origin_labels + 1)
-example.org.				      86400 IN SOA	ns.example.org. ns.example.org. 2012091001 7200 3600 2592000 1200
-example.org. 1200 IN NSEC3	1 0 10 AABBCCDD RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD A RRSIG
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-nsec3-more-labels.zone b/src/lib/datasrc/memory/tests/testdata/example.org-nsec3-more-labels.zone
deleted file mode 100644
index efebcfb..0000000
--- a/src/lib/datasrc/memory/tests/testdata/example.org-nsec3-more-labels.zone
+++ /dev/null
@@ -1,3 +0,0 @@
-;; NSEC3 names with labels != (origin_labels + 1)
-example.org.				      86400 IN SOA	ns.example.org. ns.example.org. 2012091002 7200 3600 2592000 1200
-a.b.example.org. 1200 IN NSEC3	1 0 10 AABBCCDD RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD A RRSIG
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-nsec3-signed-no-param.zone b/src/lib/datasrc/memory/tests/testdata/example.org-nsec3-signed-no-param.zone
deleted file mode 100644
index 5caa308..0000000
--- a/src/lib/datasrc/memory/tests/testdata/example.org-nsec3-signed-no-param.zone
+++ /dev/null
@@ -1,15 +0,0 @@
-;; This file intentionally removes NSEC3PARAM from example.org.nsec3-signed
-example.org.				      86400 IN SOA	ns.example.org. ns.example.org. 2012013000 7200 3600 2592000 1200
-example.org.				      86400 IN RRSIG	SOA 7 2 86400 20120301040838 20120131040838 19562 example.org. Jt9wCRLS5TQxZH0IBqrM9uMGD453rIoxYopfM9AjjRZfEx+HGlBpOZeR pGN7yLcN+URnicOD0ydLHiakaBODiZyNoYCKYG5d2ZOhL+026REnDKNM 0m5T3X3sczP+l55An/GITheTdrKt3Y1Ouc2yKI8ro8JjOxV/a4nGDWjK x9A=
-example.org.				      86400 IN NS	ns.example.org.
-example.org.				      86400 IN RRSIG	NS 7 2 86400 20120301040838 20120131040838 19562 example.org. gYXL3xK4IFdJU6TtiVuzqDBb2MeA8xB3AKtHlJGFTfTRNHyuej0ZGovx TeUYsLYmoiGYaJG66iD1tYYFq0qdj0xWq+LEa53ACtKvYf9IIwK4ijJs k0g6xCNavc6/qPppymDhN7MvoFVkW59uJa0HPWlsIIuRlEAr7xyt85vq yoA=
-example.org.				      86400 IN DNSKEY	256 3 7 AwEAAbrBkKf2gmGtG4aogZY4svIZCrOLLZlQzVHwz7WxJdTR8iEnvz/x Q/jReDroS5CBZWvzwLlhPIpsJAojx0oj0RvfJNsz3+6LN8q7x9u6+86B 85CYjTk3dcFOebgkF4fXr7/kkOX+ZY94Zk0Z1+pUC3eY4gkKcyME/Uxm O18PBTeB
-example.org.				      86400 IN RRSIG	DNSKEY 7 2 86400 20120301040838 20120131040838 19562 example.org. d0eLF8JqNHaGuBSX0ashU5c1O/wyWU43UUsKGrMQIoBDiJ588MWQOnas rwvW6vdkLNqRqCsP/B4epV/EtLL0tBsk5SHkTYbNo80gGrBufQ6YrWRr Ile8Z+h+MR4y9DybbjmuNKqaO4uQMg/X6+4HqRAKx1lmZMTcrcVeOwDM ZA4=
-;; example.org.				      0	IN NSEC3PARAM	1 0 10 AABBCCDD
-;; example.org.				      0	IN RRSIG	NSEC3PARAM 7 2 0 20120301040838 20120131040838 19562 example.org. Ggs5MiQDlXXt22Fz9DNg3Ujc0T6MBfumlRkd8/enBbJwLmqw2QXAzDEk pjUeGstCEHKzxJDJstavGoCpTDJgoV4Fd9szooMx69rzPrq9tdoM46jG xZHqw+Pv2fkRGC6aP7ZX1r3Qnpwpk47AQgATftbO4G6KcMcO8JoKE47x XLM=
-ns.example.org.				      86400 IN A	192.0.2.1
-ns.example.org.				      86400 IN RRSIG	A 7 3 86400 20120301040838 20120131040838 19562 example.org. dOH+Dxib8VcGnjLrKILsqDhS1wki6BWk1dZwpOGUGHyLWcLNW8ygWY2o r29jPhHtaFCNWpn46JebgnXDPRiQjaY3dQqL8rcf2QX1e3+Cicw1OSrs S0sUDE5DmMNEac+ZCUQ0quCStZTCldl05hlspV2RS92TpApnoOK0nXMp Uak=
-09GM5T42SMIMT7R8DF6RTG80SFMS1NLU.example.org. 1200 IN NSEC3	1 0 10 AABBCCDD RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD A RRSIG
-09GM5T42SMIMT7R8DF6RTG80SFMS1NLU.example.org. 1200 IN RRSIG	NSEC3 7 3 1200 20120301040838 20120131040838 19562 example.org. EdwMeepLf//lV+KpCAN+213Scv1rrZyj4i2OwoCP4XxxS3CWGSuvYuKO yfZc8wKRcrD/4YG6nZVXE0s5O8NahjBJmDIyVt4WkfZ6QthxGg8ggLVv cD3dFksPyiKHf/WrTOZPSsxvN5m/i1Ey6+YWS01Gf3WDCMWDauC7Nmh3 CTM=
-RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD.example.org. 1200 IN NSEC3	1 0 10 AABBCCDD 09GM5T42SMIMT7R8DF6RTG80SFMS1NLU NS SOA RRSIG DNSKEY NSEC3PARAM
-RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD.example.org. 1200 IN RRSIG	NSEC3 7 3 1200 20120301040838 20120131040838 19562 example.org. j7d8GL4YqX035FBcPPsEcSWHjWcKdlQMHLL4TB67xVNFnl4SEFQCp4OO AtPap5tkKakwgWxoQVN9XjnqrBz+oQhofDkB3aTatAjIIkcwcnrm3AYQ rTI3E03ySiRwuCPKVmHOLUV2cG6O4xzcmP+MYZcvPTS8V3F5LlaU22i7 A3E=
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-nsec3-signed.zone b/src/lib/datasrc/memory/tests/testdata/example.org-nsec3-signed.zone
deleted file mode 100644
index 9c1195f..0000000
--- a/src/lib/datasrc/memory/tests/testdata/example.org-nsec3-signed.zone
+++ /dev/null
@@ -1,14 +0,0 @@
-example.org.				      86400 IN SOA	ns.example.org. ns.example.org. 2012013000 7200 3600 2592000 1200
-example.org.				      86400 IN RRSIG	SOA 7 2 86400 20120301040838 20120131040838 19562 example.org. Jt9wCRLS5TQxZH0IBqrM9uMGD453rIoxYopfM9AjjRZfEx+HGlBpOZeR pGN7yLcN+URnicOD0ydLHiakaBODiZyNoYCKYG5d2ZOhL+026REnDKNM 0m5T3X3sczP+l55An/GITheTdrKt3Y1Ouc2yKI8ro8JjOxV/a4nGDWjK x9A=
-example.org.				      86400 IN NS	ns.example.org.
-example.org.				      86400 IN RRSIG	NS 7 2 86400 20120301040838 20120131040838 19562 example.org. gYXL3xK4IFdJU6TtiVuzqDBb2MeA8xB3AKtHlJGFTfTRNHyuej0ZGovx TeUYsLYmoiGYaJG66iD1tYYFq0qdj0xWq+LEa53ACtKvYf9IIwK4ijJs k0g6xCNavc6/qPppymDhN7MvoFVkW59uJa0HPWlsIIuRlEAr7xyt85vq yoA=
-example.org.				      86400 IN DNSKEY	256 3 7 AwEAAbrBkKf2gmGtG4aogZY4svIZCrOLLZlQzVHwz7WxJdTR8iEnvz/x Q/jReDroS5CBZWvzwLlhPIpsJAojx0oj0RvfJNsz3+6LN8q7x9u6+86B 85CYjTk3dcFOebgkF4fXr7/kkOX+ZY94Zk0Z1+pUC3eY4gkKcyME/Uxm O18PBTeB
-example.org.				      86400 IN RRSIG	DNSKEY 7 2 86400 20120301040838 20120131040838 19562 example.org. d0eLF8JqNHaGuBSX0ashU5c1O/wyWU43UUsKGrMQIoBDiJ588MWQOnas rwvW6vdkLNqRqCsP/B4epV/EtLL0tBsk5SHkTYbNo80gGrBufQ6YrWRr Ile8Z+h+MR4y9DybbjmuNKqaO4uQMg/X6+4HqRAKx1lmZMTcrcVeOwDM ZA4=
-example.org.				      0	IN NSEC3PARAM	1 0 10 AABBCCDD
-example.org.				      0	IN RRSIG	NSEC3PARAM 7 2 0 20120301040838 20120131040838 19562 example.org. Ggs5MiQDlXXt22Fz9DNg3Ujc0T6MBfumlRkd8/enBbJwLmqw2QXAzDEk pjUeGstCEHKzxJDJstavGoCpTDJgoV4Fd9szooMx69rzPrq9tdoM46jG xZHqw+Pv2fkRGC6aP7ZX1r3Qnpwpk47AQgATftbO4G6KcMcO8JoKE47x XLM=
-ns.example.org.				      86400 IN A	192.0.2.1
-ns.example.org.				      86400 IN RRSIG	A 7 3 86400 20120301040838 20120131040838 19562 example.org. dOH+Dxib8VcGnjLrKILsqDhS1wki6BWk1dZwpOGUGHyLWcLNW8ygWY2o r29jPhHtaFCNWpn46JebgnXDPRiQjaY3dQqL8rcf2QX1e3+Cicw1OSrs S0sUDE5DmMNEac+ZCUQ0quCStZTCldl05hlspV2RS92TpApnoOK0nXMp Uak=
-09GM5T42SMIMT7R8DF6RTG80SFMS1NLU.example.org. 1200 IN NSEC3	1 0 10 AABBCCDD RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD A RRSIG
-09GM5T42SMIMT7R8DF6RTG80SFMS1NLU.example.org. 1200 IN RRSIG	NSEC3 7 3 1200 20120301040838 20120131040838 19562 example.org. EdwMeepLf//lV+KpCAN+213Scv1rrZyj4i2OwoCP4XxxS3CWGSuvYuKO yfZc8wKRcrD/4YG6nZVXE0s5O8NahjBJmDIyVt4WkfZ6QthxGg8ggLVv cD3dFksPyiKHf/WrTOZPSsxvN5m/i1Ey6+YWS01Gf3WDCMWDauC7Nmh3 CTM=
-RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD.example.org. 1200 IN NSEC3	1 0 10 AABBCCDD 09GM5T42SMIMT7R8DF6RTG80SFMS1NLU NS SOA RRSIG DNSKEY NSEC3PARAM
-RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD.example.org. 1200 IN RRSIG	NSEC3 7 3 1200 20120301040838 20120131040838 19562 example.org. j7d8GL4YqX035FBcPPsEcSWHjWcKdlQMHLL4TB67xVNFnl4SEFQCp4OO AtPap5tkKakwgWxoQVN9XjnqrBz+oQhofDkB3aTatAjIIkcwcnrm3AYQ rTI3E03ySiRwuCPKVmHOLUV2cG6O4xzcmP+MYZcvPTS8V3F5LlaU22i7 A3E=
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-out-of-zone.zone b/src/lib/datasrc/memory/tests/testdata/example.org-out-of-zone.zone
deleted file mode 100644
index e3afb74..0000000
--- a/src/lib/datasrc/memory/tests/testdata/example.org-out-of-zone.zone
+++ /dev/null
@@ -1,5 +0,0 @@
-;; test zone file used for ZoneFinderContext tests.
-;; RRSIGs are (obviouslly) faked ones for testing.
-
-example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 75 3600 300 3600000 3600
-a.example.com.	  		      3600 IN A	 	192.168.0.1
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-rrsig-follows-nothing.zone b/src/lib/datasrc/memory/tests/testdata/example.org-rrsig-follows-nothing.zone
deleted file mode 100644
index ef5f887..0000000
--- a/src/lib/datasrc/memory/tests/testdata/example.org-rrsig-follows-nothing.zone
+++ /dev/null
@@ -1,5 +0,0 @@
-;; test zone file used for ZoneFinderContext tests.
-;; RRSIGs are (obviouslly) faked ones for testing.
-
-example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 68 3600 300 3600000 3600
-ns1.example.org.		      3600 IN RRSIG	A 7 3 3600 20150420235959 20051021000000 40430 example.org. FAKEFAKE
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-rrsigs.zone b/src/lib/datasrc/memory/tests/testdata/example.org-rrsigs.zone
deleted file mode 100644
index 1c780b1..0000000
--- a/src/lib/datasrc/memory/tests/testdata/example.org-rrsigs.zone
+++ /dev/null
@@ -1,8 +0,0 @@
-;; test zone file used for ZoneFinderContext tests.
-;; RRSIGs are (obviouslly) faked ones for testing.
-
-example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 74 3600 300 3600000 3600
-ns1.example.org.		      3600 IN A	 	192.168.0.1
-ns1.example.org.		      3600 IN RRSIG	A 7 3 3600 20150420235959 20051021000000 40430 example.org. FAKEFAKE
-ns1.example.org.		      3600 IN RRSIG	A 7 2 3600 20150420235959 20051021000000 40430 example.org. FAKEFAKE
-ns1.example.org.		      3600 IN AAAA 	::1
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-wildcard-dname.zone b/src/lib/datasrc/memory/tests/testdata/example.org-wildcard-dname.zone
deleted file mode 100644
index 0d03b0d..0000000
--- a/src/lib/datasrc/memory/tests/testdata/example.org-wildcard-dname.zone
+++ /dev/null
@@ -1,4 +0,0 @@
-;; test zone file with wildcard DNAME names
-
-example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 79 3600 300 3600000 3600
-*.example.org. 3600 IN DNAME dname.example.com.
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-wildcard-ns.zone b/src/lib/datasrc/memory/tests/testdata/example.org-wildcard-ns.zone
deleted file mode 100644
index 2933515..0000000
--- a/src/lib/datasrc/memory/tests/testdata/example.org-wildcard-ns.zone
+++ /dev/null
@@ -1,4 +0,0 @@
-;; test zone file with wildcard NS names
-
-example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 78 3600 300 3600000 3600
-*.example.org.			      3600 IN NS	ns1.example.org.
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org-wildcard-nsec3.zone b/src/lib/datasrc/memory/tests/testdata/example.org-wildcard-nsec3.zone
deleted file mode 100644
index feee116..0000000
--- a/src/lib/datasrc/memory/tests/testdata/example.org-wildcard-nsec3.zone
+++ /dev/null
@@ -1,4 +0,0 @@
-;; test zone file with wildcard NS names
-
-example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 79 3600 300 3600000 3600
-*.example.org. 1200 IN NSEC3	1 0 10 AABBCCDD RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD A RRSIG
diff --git a/src/lib/datasrc/memory/tests/testdata/example.org.zone b/src/lib/datasrc/memory/tests/testdata/example.org.zone
deleted file mode 100644
index e499e0d..0000000
--- a/src/lib/datasrc/memory/tests/testdata/example.org.zone
+++ /dev/null
@@ -1,81 +0,0 @@
-;; test zone file used for ZoneFinderContext tests.
-;; RRSIGs are (obviouslly) faked ones for testing.
-
-example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 67 3600 300 3600000 3600
-example.org.			      3600 IN NS	ns1.example.org.
-example.org.			      3600 IN NS	ns2.example.org.
-example.org.			      3600 IN MX	1 mx1.example.org.
-example.org.			      3600 IN MX	2 mx2.example.org.
-example.org.			      3600 IN MX	3 mx.a.example.org.
-
-ns1.example.org.		      3600 IN A		192.0.2.1
-ns1.example.org.		      3600 IN RRSIG	A 7 3 3600 20150420235959 20051021000000 40430 example.org. FAKEFAKE
-ns1.example.org.		      3600 IN AAAA	2001:db8::1
-ns1.example.org.		      3600 IN RRSIG	AAAA 7 3 3600 20150420235959 20051021000000 40430 example.org. FAKEFAKEFAKE
-ns2.example.org.		      3600 IN A		192.0.2.2
-ns2.example.org.		      3600 IN TXT	"text data"
-
-mx1.example.org.		      3600 IN A		192.0.2.10
-mx2.example.org.		      3600 IN AAAA	2001:db8::10
-
-;; delegation
-a.example.org.			      3600 IN NS	ns1.a.example.org.
-a.example.org.			      3600 IN NS	ns2.a.example.org.
-a.example.org.			      3600 IN NS	ns.example.com.
-
-ns1.a.example.org.		      3600 IN A		192.0.2.5
-ns2.a.example.org.		      3600 IN A		192.0.2.6
-ns2.a.example.org.		      3600 IN AAAA	2001:db8::6
-mx.a.example.org.		      3600 IN A		192.0.2.7
-
-;; delegation, one of its NS names is at zone cut.
-b.example.org.			      3600 IN NS	ns.b.example.org.
-b.example.org.			      3600 IN NS	b.example.org.
-b.example.org.			      3600 IN AAAA	2001:db8::8
-
-ns.b.example.org.		      3600 IN A		192.0.2.9
-
-;; The MX name is at a zone cut.  shouldn't be included in the
-;; additional section.
-mxatcut.example.org.		      3600 IN MX	1 b.example.org.
-
-;; delegation, one of its NS names is under a DNAME delegation point;
-;; another is at that point; and yet another is under DNAME below a
-;; zone cut.
-c.example.org. 	      	      3600 IN NS	ns.dname.example.org.
-c.example.org. 	      	      3600 IN NS	dname.example.org.
-c.example.org.      	      3600 IN NS	ns.deepdname.example.org.
-ns.dname.example.org.		      3600 IN A		192.0.2.11
-dname.example.org.		      3600 IN A		192.0.2.12
-ns.deepdname.example.org.	      3600 IN AAAA	2001:db8::9
-
-;; delegation, one of its NS name is at an empty non terminal.
-d.example.org. 	      	      3600 IN NS	ns.empty.example.org.
-d.example.org. 	      	      3600 IN NS	ns1.example.org.
-;; by adding these two we can create an empty RB node for
-;; ns.empty.example.org in the in-memory zone
-foo.ns.empty.example.org.     3600 IN A		192.0.2.13
-bar.ns.empty.example.org.     3600 IN A		192.0.2.14
-
-;; delegation; the NS name matches a wildcard (and there's no exact
-;; match).  One of the NS names matches an empty wildcard node, for
-;; which no additional record should be provided (or any other
-;; disruption should happen).
-e.example.org. 	      	      3600 IN NS	ns.wild.example.org.
-e.example.org. 	      	      3600 IN NS	ns.emptywild.example.org.
-e.example.org. 	      	      3600 IN NS	ns2.example.org.
-*.wild.example.org.	      3600 IN A		192.0.2.15
-a.*.emptywild.example.org.    3600 IN AAAA	2001:db8::2
-
-;; additional for an answer RRset (MX) as a result of wildcard
-;; expansion
-*.wildmx.example.org. 3600 IN MX 1 mx1.example.org.
-
-;; CNAME
-alias.example.org. 3600 IN CNAME cname.example.org.
-
-;; DNAME
-dname.example.org. 3600 IN DNAME dname.example.com.
-
-;; DNAME under a NS (strange one)
-deepdname.c.example.org. 3600 IN DNAME deepdname.example.com.
diff --git a/src/lib/datasrc/memory/tests/treenode_rrset_unittest.cc b/src/lib/datasrc/memory/tests/treenode_rrset_unittest.cc
deleted file mode 100644
index 182cca6..0000000
--- a/src/lib/datasrc/memory/tests/treenode_rrset_unittest.cc
+++ /dev/null
@@ -1,591 +0,0 @@
-// 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 <util/buffer.h>
-#include <util/memory_segment_local.h>
-
-#include <datasrc/memory/treenode_rrset.h>
-#include <datasrc/memory/rdataset.h>
-#include <datasrc/memory/rdata_serialization.h>
-#include <datasrc/memory/zone_data.h>
-
-#include <util/unittests/wiredata.h>
-#include <testutils/dnsmessage_test.h>
-
-#include <gtest/gtest.h>
-
-#include <boost/shared_ptr.hpp>
-
-#include <string>
-#include <vector>
-
-using std::vector;
-using std::string;
-using namespace isc::dns;
-using namespace isc::dns::rdata;
-using namespace isc::datasrc::memory;
-using namespace isc::testutils;
-using isc::util::unittests::matchWireData;
-using isc::util::OutputBuffer;
-
-namespace {
-
-class TreeNodeRRsetTest : public ::testing::Test {
-protected:
-    TreeNodeRRsetTest() :
-        rrclass_(RRClass::IN()),
-        origin_name_("example.com"), www_name_("www.example.com"),
-        wildcard_name_("*.example.com"), match_name_("match.example.com"),
-        ns_rrset_(textToRRset("example.com. 3600 IN NS ns.example.com.")),
-        a_rrset_(textToRRset("www.example.com. 3600 IN A 192.0.2.1\n"
-                             "www.example.com. 3600 IN A 192.0.2.2")),
-        aaaa_rrset_(textToRRset("www.example.com. 3600 IN AAAA "
-                                "2001:db8::1\n")),
-        dname_rrset_(textToRRset("example.com. 3600 IN DNAME d.example.org.")),
-        a_rrsig_rrset_(textToRRset("www.example.com. 3600 IN RRSIG "
-                                   "A 5 2 3600 20120814220826 20120715220826 "
-                                   "1234 example.com. FAKE")),
-        aaaa_rrsig_rrset_(textToRRset("www.example.com. 3600 IN RRSIG AAAA 5 2"
-                                      " 3600 20120814220826 20120715220826 "
-                                      "1234 example.com. FAKE\n"
-                                      "www.example.com. 3600 IN RRSIG AAAA 5 2"
-                                      " 3600 20120814220826 20120715220826 "
-                                      "4321 example.com. FAKE\n")),
-        txt_rrsig_rrset_(textToRRset("www.example.com. 3600 IN RRSIG TXT 5 2"
-                                     " 3600 20120814220826 20120715220826 "
-                                     "1234 example.com. FAKE\n")),
-        wildmatch_rrset_(textToRRset(
-                             "match.example.com. 3600 IN A 192.0.2.1\n"
-                             "match.example.com. 3600 IN A 192.0.2.2")),
-        wildmatch_rrsig_rrset_(textToRRset(
-                                   "match.example.com. 3600 IN RRSIG "
-                                   "A 5 2 3600 20120814220826 20120715220826 "
-                                   "1234 example.com. FAKE")),
-        zone_data_(NULL), origin_node_(NULL), www_node_(NULL),
-        wildcard_node_(NULL), ns_rdataset_(NULL), dname_rdataset_(NULL),
-        a_rdataset_(NULL), aaaa_rdataset_(NULL), rrsig_only_rdataset_(NULL),
-        wildcard_rdataset_(NULL)
-    {}
-    void SetUp() {
-        // We create some common test data here in SetUp() so it will be
-        // as exception safe as possible.
-
-        zone_data_ = ZoneData::create(mem_sgmt_, origin_name_);
-
-        zone_data_->insertName(mem_sgmt_, origin_name_, &origin_node_);
-        ns_rdataset_ = RdataSet::create(mem_sgmt_, encoder_, ns_rrset_,
-                                        ConstRRsetPtr());
-        origin_node_->setData(ns_rdataset_);
-        dname_rdataset_ = RdataSet::create(mem_sgmt_, encoder_, dname_rrset_,
-                                           ConstRRsetPtr());
-        ns_rdataset_->next = dname_rdataset_;
-
-        zone_data_->insertName(mem_sgmt_, www_name_, &www_node_);
-        a_rdataset_ = RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
-                                       a_rrsig_rrset_);
-        www_node_->setData(a_rdataset_);
-
-        aaaa_rdataset_ = RdataSet::create(mem_sgmt_, encoder_, aaaa_rrset_,
-                                          aaaa_rrsig_rrset_);
-        a_rdataset_->next = aaaa_rdataset_;
-
-        // A rare (half broken) case of RRSIG-only set
-        rrsig_only_rdataset_ = RdataSet::create(mem_sgmt_, encoder_,
-                                                ConstRRsetPtr(),
-                                                txt_rrsig_rrset_);
-        aaaa_rdataset_->next = rrsig_only_rdataset_;
-
-        zone_data_->insertName(mem_sgmt_, wildcard_name_, &wildcard_node_);
-        wildcard_rdataset_ = RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
-                                              a_rrsig_rrset_);
-        wildcard_node_->setData(wildcard_rdataset_);
-    }
-    void TearDown() {
-        ZoneData::destroy(mem_sgmt_, zone_data_, rrclass_);
-        // detect any memory leak
-        EXPECT_TRUE(mem_sgmt_.allMemoryDeallocated());
-    }
-
-    const RRClass rrclass_;
-    const Name origin_name_, www_name_, wildcard_name_, match_name_;
-    isc::util::MemorySegmentLocal mem_sgmt_;
-    RdataEncoder encoder_;
-    MessageRenderer renderer_, renderer_expected_;
-    ConstRRsetPtr ns_rrset_, a_rrset_, aaaa_rrset_, dname_rrset_,
-        a_rrsig_rrset_, aaaa_rrsig_rrset_, txt_rrsig_rrset_,
-        wildmatch_rrset_, wildmatch_rrsig_rrset_;
-    ZoneData* zone_data_;
-    ZoneNode* origin_node_;
-    ZoneNode* www_node_;
-    ZoneNode* wildcard_node_;
-    RdataSet* ns_rdataset_;
-    RdataSet* dname_rdataset_;
-    RdataSet* a_rdataset_;
-    RdataSet* aaaa_rdataset_;
-    RdataSet* rrsig_only_rdataset_;
-    RdataSet* wildcard_rdataset_; // for wildcard (type doesn't matter much)
-};
-
-// Check some trivial fields of a constructed TreeNodeRRset (passed as
-// AbstractRRset as we'd normally use it in polymorphic way).
-// Other complicated fields are checked through rendering tests.
-void
-checkBasicFields(const AbstractRRset& actual_rrset, const Name& expected_name,
-                 const RRClass& expected_class, const RRType& expected_type,
-                 const uint32_t expected_ttl,
-                 size_t expected_rdatacount, size_t expected_sigcount)
-{
-    EXPECT_EQ(expected_name, actual_rrset.getName());
-    EXPECT_EQ(expected_class, actual_rrset.getClass());
-    EXPECT_EQ(expected_type, actual_rrset.getType());
-    EXPECT_EQ(RRTTL(expected_ttl), actual_rrset.getTTL());
-    EXPECT_EQ(expected_rdatacount, actual_rrset.getRdataCount());
-    EXPECT_EQ(expected_sigcount, actual_rrset.getRRsigDataCount());
-}
-
-// The following two are trivial wrapper to create a shared pointer
-// version of TreeNodeRRset object in order to work around dubious
-// behavior of some C++ compiler: they reject getting a const reference to
-// a temporary non-copyable object.
-boost::shared_ptr<TreeNodeRRset>
-createRRset(const RRClass& rrclass, const ZoneNode* node,
-            const RdataSet* rdataset, bool dnssec_ok)
-{
-    return (boost::shared_ptr<TreeNodeRRset>(
-                new TreeNodeRRset(rrclass, node, rdataset, dnssec_ok)));
-}
-
-boost::shared_ptr<TreeNodeRRset>
-createRRset(const Name& realname, const RRClass& rrclass, const ZoneNode* node,
-            const RdataSet* rdataset, bool dnssec_ok)
-{
-    return (boost::shared_ptr<TreeNodeRRset>(
-                new TreeNodeRRset(realname, rrclass, node, rdataset,
-                                  dnssec_ok)));
-}
-
-TEST_F(TreeNodeRRsetTest, create) {
-    // Constructed with RRSIG, and it should be visible.
-    checkBasicFields(*createRRset(rrclass_, www_node_, a_rdataset_, true),
-                     www_name_, rrclass_, RRType::A(), 3600, 2, 1);
-    // Constructed with RRSIG, and it should be invisible.
-    checkBasicFields(*createRRset(rrclass_, www_node_, a_rdataset_, false),
-                     www_name_, rrclass_, RRType::A(), 3600, 2, 0);
-    // Constructed without RRSIG, and it would be visible (but of course won't)
-    checkBasicFields(*createRRset(rrclass_, origin_node_, ns_rdataset_, true),
-                     origin_name_, rrclass_, RRType::NS(), 3600, 1, 0);
-    // Constructed without RRSIG, and it should be visible
-    checkBasicFields(*createRRset(rrclass_, origin_node_, ns_rdataset_, false),
-                     origin_name_, rrclass_, RRType::NS(), 3600, 1, 0);
-    // RRSIG-only case (note the RRset's type is covered type)
-    checkBasicFields(*createRRset(rrclass_, www_node_, rrsig_only_rdataset_,
-                                  true),
-                     www_name_, rrclass_, RRType::TXT(), 3600, 0, 1);
-    // RRSIG-only case (note the RRset's type is covered type), but it's
-    // invisible
-    checkBasicFields(*createRRset(rrclass_, www_node_, rrsig_only_rdataset_,
-                                  false),
-                     www_name_, rrclass_, RRType::TXT(), 3600, 0, 0);
-    // Wildcard substitution
-    checkBasicFields(*createRRset(match_name_, rrclass_,
-                                  wildcard_node_, wildcard_rdataset_,
-                                  true),
-                     match_name_, rrclass_, RRType::A(), 3600, 2, 1);
-}
-
-// The following two templated functions are helper to encapsulate the
-// concept truncation and handle MessageRenderer and OutputBuffer transparently
-// in templated test cases.
-template <typename OutputType>
-void
-setOutputLengthLimit(OutputType& output, size_t len_limit) {
-    output.setLengthLimit(len_limit);
-}
-template <>
-void
-setOutputLengthLimit<OutputBuffer>(OutputBuffer&, size_t) {
-}
-
-template <typename OutputType>
-bool
-isOutputTruncated(OutputType& output) {
-    return (output.isTruncated());
-}
-template <>
-bool
-isOutputTruncated<OutputBuffer>(OutputBuffer&) {
-    return (false);
-}
-
-// Templated so we so can support OutputBuffer version of toWire().
-// We use the above helper templated functions for some renderer only methods.
-// We test two sets of cases: normal rendering case and case when truncation
-// is expected.  The latter is effectively for MessageRenderer only.
-// If len_limit == 0, we consider it the normal case; otherwise it's for
-// truncation.  prepended_name isn't used for the truncation case.
-template <typename OutputType>
-void
-checkToWireResult(OutputType& expected_output, OutputType& actual_output,
-                  const AbstractRRset& actual_rrset,
-                  const Name& prepended_name,
-                  ConstRRsetPtr rrset, ConstRRsetPtr rrsig_rrset,
-                  bool dnssec_ok,
-                  size_t len_limit = 0,
-                  size_t expected_result = 0)
-{
-    expected_output.clear();
-    actual_output.clear();
-
-    if (len_limit == 0) {       // normal rendering
-        // Prepare "actual" rendered data.  We prepend a name to confirm the
-        // owner name should be compressed in both cases.
-        prepended_name.toWire(actual_output);
-        const size_t rdata_count = rrset ? rrset->getRdataCount() : 0;
-        const int expected_ret = (dnssec_ok && rrsig_rrset) ?
-            rdata_count + rrsig_rrset->getRdataCount() : rdata_count;
-        EXPECT_EQ(expected_ret, actual_rrset.toWire(actual_output));
-    } else {                    // truncation
-        setOutputLengthLimit(actual_output, len_limit);
-        EXPECT_EQ(expected_result, actual_rrset.toWire(actual_output));
-        EXPECT_TRUE(isOutputTruncated(actual_output)); // always true here
-    }
-
-    // Prepare "expected" data.
-    if (len_limit == 0) {       // normal rendering
-        prepended_name.toWire(expected_output);
-    } else {                    // truncation
-        setOutputLengthLimit(expected_output, len_limit);
-    }
-    if (rrset) {
-        rrset->toWire(expected_output);
-    }
-    if (!isOutputTruncated(expected_output) && dnssec_ok && rrsig_rrset) {
-        rrsig_rrset->toWire(expected_output);
-    }
-
-    // Compare the two.
-    matchWireData(expected_output.getData(), expected_output.getLength(),
-                  actual_output.getData(), actual_output.getLength());
-}
-
-TEST_F(TreeNodeRRsetTest, toWire) {
-    MessageRenderer expected_renderer, actual_renderer;
-    OutputBuffer expected_buffer(0), actual_buffer(0);
-
-    {
-        SCOPED_TRACE("with RRSIG, DNSSEC OK");
-        const TreeNodeRRset rrset(rrclass_, www_node_, a_rdataset_, true);
-        checkToWireResult(expected_renderer, actual_renderer, rrset,
-                          www_name_, a_rrset_, a_rrsig_rrset_, true);
-        // Currently the buffer version throws
-        EXPECT_THROW(
-            checkToWireResult(expected_buffer, actual_buffer, rrset,
-                              www_name_, a_rrset_, a_rrsig_rrset_, true),
-            isc::Unexpected);
-    }
-
-    {
-        SCOPED_TRACE("with RRSIG, DNSSEC not OK");
-        const TreeNodeRRset rrset(rrclass_, www_node_, a_rdataset_, false);
-        checkToWireResult(expected_renderer, actual_renderer, rrset,
-                          www_name_, a_rrset_, a_rrsig_rrset_, false);
-    }
-
-    {
-        SCOPED_TRACE("without RRSIG, DNSSEC OK");
-        const TreeNodeRRset rrset(rrclass_, origin_node_, ns_rdataset_, true);
-        checkToWireResult(expected_renderer, actual_renderer, rrset,
-                          origin_name_, ns_rrset_, ConstRRsetPtr(), true);
-    }
-
-    {
-        SCOPED_TRACE("without RRSIG, DNSSEC not OK");
-        const TreeNodeRRset rrset(rrclass_, origin_node_, ns_rdataset_,
-                                  false);
-        checkToWireResult(expected_renderer, actual_renderer, rrset,
-                          origin_name_, ns_rrset_, ConstRRsetPtr(), false);
-    }
-
-    {
-        // RDATA of DNAME DR shouldn't be compressed.  Prepending "example.org"
-        // will check that.
-        SCOPED_TRACE("uncompressed RDATA");
-        const TreeNodeRRset rrset(rrclass_, origin_node_, dname_rdataset_,
-                                  false);
-        checkToWireResult(expected_renderer, actual_renderer, rrset,
-                          Name("example.org"), dname_rrset_, ConstRRsetPtr(),
-                          false);
-    }
-
-    {
-        SCOPED_TRACE("wildcard with RRSIG");
-        checkToWireResult(expected_renderer, actual_renderer,
-                          *createRRset(match_name_, rrclass_, wildcard_node_,
-                                       wildcard_rdataset_, true),
-                          origin_name_, wildmatch_rrset_,
-                          wildmatch_rrsig_rrset_, true);
-    }
-
-    {
-        SCOPED_TRACE("wildcard without RRSIG");
-        checkToWireResult(expected_renderer, actual_renderer,
-                          *createRRset(match_name_, rrclass_, wildcard_node_,
-                                       wildcard_rdataset_, false),
-                          origin_name_, wildmatch_rrset_,
-                          wildmatch_rrsig_rrset_, false);
-    }
-
-    {
-        // Very unusual case: the set only contains RRSIG (already rare)
-        // and it's requested to be dumped to wire (can only happen in
-        // ANY or type-RRSIG queries, which are rare also).  But can still
-        // happen.
-        SCOPED_TRACE("RRSIG only, DNSSEC OK");
-        const TreeNodeRRset rrset(rrclass_, www_node_, rrsig_only_rdataset_,
-                                  true);
-        checkToWireResult(expected_renderer, actual_renderer, rrset,
-                          www_name_, ConstRRsetPtr(), txt_rrsig_rrset_,true);
-    }
-
-    {
-        // Similar to the previous case, but DNSSEC records aren't requested.
-        // In practice this case wouldn't happen, but API-wise possible, so
-        // we test it explicitly.
-        SCOPED_TRACE("RRSIG only, DNSSEC not OK");
-        const TreeNodeRRset rrset(rrclass_, www_node_, rrsig_only_rdataset_,
-                                  false);
-        checkToWireResult(expected_renderer, actual_renderer, rrset,
-                          www_name_, ConstRRsetPtr(), txt_rrsig_rrset_,false);
-    }
-}
-
-TEST_F(TreeNodeRRsetTest, toWireTruncated) {
-    MessageRenderer expected_renderer, actual_renderer;
-    // dummy parameter to checkToWireResult (unused for the this test case)
-    const Name& name = Name::ROOT_NAME();
-
-    // Set the truncation limit to name len + 14 bytes of fixed data for A RR
-    // (type, class, TTL, rdlen, and 4-byte IPv4 address).  Then we can only
-    // render just one RR, without any garbage trailing data.
-    checkToWireResult(expected_renderer, actual_renderer,
-                      *createRRset(rrclass_, www_node_, a_rdataset_, true),
-                      name, a_rrset_, a_rrsig_rrset_, true,
-                      www_name_.getLength() + 14,
-                      1);   // 1 main RR, no RRSIG
-
-    // The first main RRs should fit in the renderer (the name will be
-    // fully compressed, so its size is 2 bytes), but the RRSIG doesn't.
-    checkToWireResult(expected_renderer, actual_renderer,
-                      *createRRset(rrclass_, www_node_, a_rdataset_, true),
-                      name, a_rrset_, a_rrsig_rrset_, true,
-                      www_name_.getLength() + 14 + 2 + 14,
-                      2);   // 2 main RR, no RRSIG
-
-    // This RRset has one main RR and two RRSIGs.  Rendering the second RRSIG
-    // causes truncation.
-    // First, compute the rendered length for the main RR and a single RRSIG.
-    // The length of the RRSIG should be the same if we "accidentally"
-    // rendered the RRSIG for the A RR (which only contains one RRSIG).
-    expected_renderer.clear();
-    aaaa_rrset_->toWire(expected_renderer);
-    a_rrsig_rrset_->toWire(expected_renderer);
-    const size_t limit_len = expected_renderer.getLength();
-    // Then perform the test
-    checkToWireResult(expected_renderer, actual_renderer,
-                      *createRRset(rrclass_, www_node_, aaaa_rdataset_, true),
-                      name, aaaa_rrset_, aaaa_rrsig_rrset_, true, limit_len,
-                      2);   // 1 main RR, 1 RRSIG
-
-    // RRSIG only case.  Render length limit being 1, so it won't fit,
-    // and will cause truncation.
-    checkToWireResult(expected_renderer, actual_renderer,
-                      *createRRset(rrclass_, www_node_, rrsig_only_rdataset_,
-                                   true),
-                      name, ConstRRsetPtr(), txt_rrsig_rrset_, true, 1,
-                      0);   // no RR
-}
-
-void
-checkRdataIterator(const vector<string>& expected, RdataIteratorPtr rit) {
-    for (vector<string>::const_iterator it = expected.begin();
-         it != expected.end();
-         ++it)
-    {
-        ASSERT_FALSE(rit->isLast());
-        EXPECT_EQ(*it, rit->getCurrent().toText());
-        rit->next();
-    }
-    // We should have reached the end of RDATA
-    EXPECT_TRUE(rit->isLast());
-
-    // move to the first RDATA again, and check the value.
-    rit->first();
-    if (!expected.empty()) {
-        EXPECT_EQ(expected[0], rit->getCurrent().toText());
-    } else {
-        EXPECT_TRUE(rit->isLast());
-    }
-}
-
-TEST_F(TreeNodeRRsetTest, getRdataIterator) {
-    // This RRset should have 2 A RDATAs
-    vector<string> expected;
-    expected.push_back("192.0.2.1");
-    expected.push_back("192.0.2.2");
-    checkRdataIterator(expected,
-                       TreeNodeRRset(rrclass_, www_node_, a_rdataset_, true).
-                       getRdataIterator());
-
-    // The iterator shouldn't work different with or without RRSIG
-    checkRdataIterator(expected,
-                       TreeNodeRRset(rrclass_, www_node_, a_rdataset_, false).
-                       getRdataIterator());
-
-    // This RRset should have 1 NS RDATA (containing name field)
-    expected.clear();
-    expected.push_back("ns.example.com.");
-    checkRdataIterator(expected,
-                       TreeNodeRRset(rrclass_, origin_node_, ns_rdataset_,
-                                     false).getRdataIterator());
-
-    // RRSIG only.  Iterator will be empty and shouldn't cause any disruption.
-    expected.clear();
-    checkRdataIterator(expected,
-                       TreeNodeRRset(rrclass_, www_node_, rrsig_only_rdataset_,
-                                     true).getRdataIterator());
-}
-
-void
-checkToText(const AbstractRRset& actual_rrset,
-            ConstRRsetPtr expected_rrset, ConstRRsetPtr expected_sig_rrset)
-{
-    const string actual_text = actual_rrset.toText();
-    const string expected_text =
-        (expected_rrset ? expected_rrset->toText() : "") +
-        (expected_sig_rrset ? expected_sig_rrset->toText() : "");
-    EXPECT_EQ(expected_text, actual_text);
-}
-
-TEST_F(TreeNodeRRsetTest, toText) {
-    // Constructed with RRSIG, and it should be visible.
-    checkToText(*createRRset(rrclass_, www_node_, a_rdataset_, true),
-                a_rrset_, a_rrsig_rrset_);
-    // Constructed with RRSIG, and it should be invisible.
-    checkToText(*createRRset(rrclass_, www_node_, a_rdataset_, false),
-                a_rrset_, ConstRRsetPtr());
-    // Constructed without RRSIG, and it would be visible (but of course won't)
-    checkToText(*createRRset(rrclass_, origin_node_, ns_rdataset_, true),
-                ns_rrset_, ConstRRsetPtr());
-    // Constructed without RRSIG, and it should be visible
-    checkToText(*createRRset(rrclass_, origin_node_, ns_rdataset_, false),
-                ns_rrset_, ConstRRsetPtr());
-    // Wildcard expanded name with RRSIG
-    checkToText(*createRRset(match_name_, rrclass_, wildcard_node_,
-                             wildcard_rdataset_, true),
-                wildmatch_rrset_, wildmatch_rrsig_rrset_);
-    // Wildcard expanded name without RRSIG
-    checkToText(*createRRset(match_name_, rrclass_, wildcard_node_,
-                             wildcard_rdataset_, false),
-                wildmatch_rrset_, ConstRRsetPtr());
-    // RRSIG case
-    checkToText(*createRRset(rrclass_, www_node_, rrsig_only_rdataset_,
-                             true),
-                ConstRRsetPtr(), txt_rrsig_rrset_);
-    // Similar to the previous case, but completely empty.
-    checkToText(*createRRset(rrclass_, www_node_, rrsig_only_rdataset_,
-                             false),
-                ConstRRsetPtr(), ConstRRsetPtr());
-}
-
-TEST_F(TreeNodeRRsetTest, isSameKind) {
-    const TreeNodeRRset rrset(rrclass_, www_node_, a_rdataset_, true);
-
-    // Same name (node), same type (rdataset) => same kind
-    EXPECT_TRUE(rrset.isSameKind(*createRRset(rrclass_, www_node_,
-                                              a_rdataset_, true)));
-
-    // Same name (node), different type (rdataset) => not same kind
-    EXPECT_FALSE(rrset.isSameKind(*createRRset(rrclass_, www_node_,
-                                               aaaa_rdataset_, true)));
-
-    // Different name, different type => not same kind
-    EXPECT_FALSE(rrset.isSameKind(*createRRset(rrclass_, origin_node_,
-                                               ns_rdataset_, true)));
-
-    // Different name, same type => not same kind.
-    // Note: this shouldn't happen in our in-memory data source implementation,
-    // but API doesn't prohibit it.
-    EXPECT_FALSE(rrset.isSameKind(*createRRset(rrclass_, origin_node_,
-                                               a_rdataset_, true)));
-
-    // Wildcard and expanded RRset
-    const TreeNodeRRset wildcard_rrset(rrclass_, wildcard_node_,
-                                       wildcard_rdataset_, true);
-    const TreeNodeRRset match_rrset(match_name_, rrclass_, wildcard_node_,
-                                    wildcard_rdataset_, true);
-    EXPECT_FALSE(wildcard_rrset.isSameKind(match_rrset));
-    EXPECT_FALSE(match_rrset.isSameKind(wildcard_rrset));
-
-    // Both are wildcard expanded, and have different names
-    const TreeNodeRRset match2_rrset(Name("match2.example.com"), rrclass_,
-                                     wildcard_node_, wildcard_rdataset_, true);
-    EXPECT_FALSE(match_rrset.isSameKind(match2_rrset));
-    EXPECT_FALSE(match2_rrset.isSameKind(match_rrset));
-
-    // Pathological case.  "badwild" is constructed as if expanded due to
-    // a wildcard, but has the same owner name of the wildcard itself.
-    // Technically, they should be considered of the same kind, but this
-    // implementation considers they are not.  But this case shouldn't happen
-    // as long as the RRsets are only constructed inside the in-memory
-    // zone finder implementation.
-    const TreeNodeRRset badwild_rrset(wildcard_name_, rrclass_, wildcard_node_,
-                                      wildcard_rdataset_, true);
-    EXPECT_FALSE(wildcard_rrset.isSameKind(badwild_rrset));
-    EXPECT_EQ(wildcard_rrset.toText(), badwild_rrset.toText());
-
-    // Pathological case:  Same name, same type, but different class.
-    // This case should be impossible because if the RRsets share the same
-    // tree node, they must belong to the same RR class.  This case is
-    // a caller's bug, and the isSameKind() implementation returns the
-    // "wrong" (= true) answer.
-    EXPECT_TRUE(rrset.isSameKind(*createRRset(RRClass::CH(), www_node_,
-                                              a_rdataset_, true)));
-
-    // Same kind of different RRset class
-    EXPECT_TRUE(rrset.isSameKind(*a_rrset_));
-
-    // Different kind of different RRset class
-    EXPECT_FALSE(rrset.isSameKind(*aaaa_rrset_));
-}
-
-TEST_F(TreeNodeRRsetTest, unexpectedMethods) {
-    // Note: buffer version of toWire() is checked in the toWire test.
-
-    TreeNodeRRset rrset(rrclass_, www_node_, a_rdataset_, true);
-
-    EXPECT_THROW(rrset.setTTL(RRTTL(0)), isc::Unexpected);
-    EXPECT_THROW(rrset.setName(Name("example")), isc::Unexpected);
-    EXPECT_THROW(rrset.addRdata(createRdata(RRType::A(), rrclass_, "0.0.0.0")),
-                 isc::Unexpected);
-    EXPECT_THROW(rrset.getRRsig(), isc::Unexpected);
-    RdataPtr sig_rdata = createRdata(
-        RRType::RRSIG(), rrclass_,
-        "A 5 2 3600 20120814220826 20120715220826 5300 example.com. FAKE");
-    EXPECT_THROW(rrset.addRRsig(sig_rdata), isc::Unexpected);
-    EXPECT_THROW(rrset.addRRsig(*a_rrsig_rrset_), isc::Unexpected);
-    EXPECT_THROW(rrset.addRRsig(a_rrsig_rrset_), isc::Unexpected);
-    EXPECT_THROW(rrset.addRRsig(RRsetPtr()), isc::Unexpected);
-    EXPECT_THROW(rrset.removeRRsig(), isc::Unexpected);
-}
-}
diff --git a/src/lib/datasrc/memory/tests/zone_data_unittest.cc b/src/lib/datasrc/memory/tests/zone_data_unittest.cc
deleted file mode 100644
index d15fe8b..0000000
--- a/src/lib/datasrc/memory/tests/zone_data_unittest.cc
+++ /dev/null
@@ -1,255 +0,0 @@
-// 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 "memory_segment_test.h"
-
-#include <dns/rdataclass.h>
-
-#include <exceptions/exceptions.h>
-
-#include <dns/name.h>
-#include <dns/labelsequence.h>
-#include <dns/rrclass.h>
-
-#include <datasrc/memory/rdata_serialization.h>
-#include <datasrc/memory/rdataset.h>
-#include <datasrc/memory/zone_data.h>
-
-#include <testutils/dnsmessage_test.h>
-
-#include <gtest/gtest.h>
-
-#include <new>                  // for bad_alloc
-#include <string>
-
-using namespace isc::dns;
-using namespace isc::dns::rdata;
-using namespace isc::datasrc::memory;
-using namespace isc::datasrc::memory::test;
-using namespace isc::testutils;
-
-namespace {
-
-// With this single fixture we'll test both NSEC3Data and ZoneData
-class ZoneDataTest : public ::testing::Test {
-protected:
-    ZoneDataTest() :
-        nsec3_data_(NULL), param_rdata_("1 0 12 aabbccdd"),
-        param_rdata_nosalt_("1 1 10 -"),
-        param_rdata_largesalt_("2 0 5 " + std::string(255 * 2, 'a')),
-        nsec3_rdata_("1 0 12 aabbccdd TDK23RP6 SOA"),
-        nsec3_rdata_nosalt_("1 1 10 - TDK23RP6 SOA"),
-        nsec3_rdata_largesalt_("2 0 5 " + std::string(255 * 2, 'a') +
-                               " TDK23RP6 SOA"),
-        zname_("example.com"),
-        zone_data_(ZoneData::create(mem_sgmt_, zname_)),
-        a_rrset_(textToRRset("www.example.com. 3600 IN A 192.0.2.1")),
-        aaaa_rrset_(textToRRset("www.example.com. 3600 IN AAAA 2001:db8::1")),
-        nsec3_rrset_(textToRRset("TDK23RP6.example.com. 3600 IN NSEC3 "
-                                 "1 0 12 aabbccdd TDK23RP6 SOA"))
-    {}
-    void TearDown() {
-        if (nsec3_data_ != NULL) {
-            NSEC3Data::destroy(mem_sgmt_, nsec3_data_, RRClass::IN());
-        }
-        if (zone_data_ != NULL) {
-            ZoneData::destroy(mem_sgmt_, zone_data_, RRClass::IN());
-        }
-        // detect any memory leak in the test memory segment
-        EXPECT_TRUE(mem_sgmt_.allMemoryDeallocated());
-    }
-
-    MemorySegmentTest mem_sgmt_;
-    NSEC3Data* nsec3_data_;
-    const generic::NSEC3PARAM param_rdata_, param_rdata_nosalt_,
-        param_rdata_largesalt_;
-    const generic::NSEC3 nsec3_rdata_, nsec3_rdata_nosalt_,
-        nsec3_rdata_largesalt_;
-    const Name zname_;
-    ZoneData* zone_data_;
-    const ConstRRsetPtr a_rrset_, aaaa_rrset_, nsec3_rrset_;
-    RdataEncoder encoder_;
-};
-
-// Shared by both test cases using NSEC3 and NSEC3PARAM Rdata
-template <typename RdataType>
-void
-checkNSEC3Data(MemorySegmentTest& mem_sgmt, const RdataType& expect_rdata) {
-    NSEC3Data* nsec3_data = NSEC3Data::create(mem_sgmt, expect_rdata);
-
-    // Internal tree should be created and empty.
-    EXPECT_EQ(0, nsec3_data->getNSEC3Tree().getNodeCount());
-
-    EXPECT_EQ(expect_rdata.getHashalg(), nsec3_data->hashalg);
-    EXPECT_EQ(expect_rdata.getFlags(), nsec3_data->flags);
-    EXPECT_EQ(expect_rdata.getIterations(), nsec3_data->iterations);
-    EXPECT_EQ(expect_rdata.getSalt().size(), nsec3_data->getSaltLen());
-    if (expect_rdata.getSalt().size() > 0) {
-        EXPECT_EQ(0, memcmp(&expect_rdata.getSalt()[0],
-                            nsec3_data->getSaltData(),
-                            expect_rdata.getSalt().size()));
-    }
-
-    NSEC3Data::destroy(mem_sgmt, nsec3_data, RRClass::IN());
-}
-
-void
-checkFindRdataSet(const ZoneTree& tree, const Name& name, RRType type,
-                  const RdataSet* expected_set)
-{
-    ZoneNode* node = NULL;
-    tree.find(name, &node);
-    ASSERT_NE(static_cast<ZoneNode*>(NULL), node);
-    EXPECT_EQ(expected_set, RdataSet::find(node->getData(), type));
-}
-
-TEST_F(ZoneDataTest, createNSEC3Data) {
-    // Create an NSEC3Data object from various types of RDATA (of NSEC3PARAM
-    // and of NSEC3), check if the resulting parameters match.
-    checkNSEC3Data(mem_sgmt_, param_rdata_); // one 'usual' form of params
-    checkNSEC3Data(mem_sgmt_, param_rdata_nosalt_); // empty salt
-    checkNSEC3Data(mem_sgmt_, param_rdata_largesalt_); // max-len salt
-
-    // Same concepts of the tests, using NSEC3 RDATA.
-    checkNSEC3Data(mem_sgmt_, nsec3_rdata_);
-    checkNSEC3Data(mem_sgmt_, nsec3_rdata_nosalt_);
-    checkNSEC3Data(mem_sgmt_, nsec3_rdata_largesalt_);
-}
-
-TEST_F(ZoneDataTest, addNSEC3) {
-    nsec3_data_ = NSEC3Data::create(mem_sgmt_, param_rdata_);
-
-    ZoneNode* node = NULL;
-    nsec3_data_->insertName(mem_sgmt_, nsec3_rrset_->getName(), &node);
-    ASSERT_NE(static_cast<ZoneNode*>(NULL), node);
-    EXPECT_TRUE(node->isEmpty()); // initially it should be empty
-
-    RdataSet* rdataset_nsec3 =
-        RdataSet::create(mem_sgmt_, encoder_, nsec3_rrset_, ConstRRsetPtr());
-    node->setData(rdataset_nsec3);
-
-    // Confirm we can find the added ones from the zone data.
-    checkFindRdataSet(nsec3_data_->getNSEC3Tree(), nsec3_rrset_->getName(),
-                      RRType::NSEC3(), rdataset_nsec3);
-
-    // TearDown() will confirm there's no leak on destroy
-}
-
-TEST_F(ZoneDataTest, getOriginNode) {
-    EXPECT_EQ(LabelSequence(zname_), zone_data_->getOriginNode()->getLabels());
-}
-
-TEST_F(ZoneDataTest, exceptionSafetyOnCreate) {
-    // Note: below, we use our knowledge of how memory allocation happens
-    // within the NSEC3Data, the zone data and the underlying domain tree
-    // implementation.  We'll emulate rare situations where allocate() fails
-    // with an exception, and confirm it doesn't cause any harsh disruption
-    // or leak.
-
-    // Creating internal NSEC3 tree will succeed, but allocation of NSEC3Data
-    // will fail due to bad_alloc.  It shouldn't cause memory leak
-    // (that would be caught in TearDown()).
-    mem_sgmt_.setThrowCount(2);
-    EXPECT_THROW(NSEC3Data::create(mem_sgmt_, param_rdata_), std::bad_alloc);
-
-    // allocate() will throw on the insertion of the origin node.
-    mem_sgmt_.setThrowCount(2);
-    EXPECT_THROW(ZoneData::create(mem_sgmt_, zname_), std::bad_alloc);
-
-    // allocate() will throw on creating the zone data.
-    mem_sgmt_.setThrowCount(3);
-    EXPECT_THROW(ZoneData::create(mem_sgmt_, zname_), std::bad_alloc);
-
-    // These incomplete create() attempts shouldn't cause memory leak
-    // (that would be caught in TearDown()).
-}
-
-TEST_F(ZoneDataTest, addRdataSets) {
-    // Insert a name to the zone, and add a couple the data (RdataSet) objects
-    // to the corresponding node.
-
-    ZoneNode* node = NULL;
-    zone_data_->insertName(mem_sgmt_, a_rrset_->getName(), &node);
-    ASSERT_NE(static_cast<ZoneNode*>(NULL), node);
-    EXPECT_TRUE(node->isEmpty()); // initially it should be empty
-
-    RdataSet* rdataset_a =
-        RdataSet::create(mem_sgmt_, encoder_, a_rrset_, ConstRRsetPtr());
-    node->setData(rdataset_a);
-
-    RdataSet* rdataset_aaaa =
-        RdataSet::create(mem_sgmt_, encoder_, aaaa_rrset_, ConstRRsetPtr());
-    // make a linked list and replace the list head
-    rdataset_aaaa->next = rdataset_a;
-    node->setData(rdataset_aaaa);
-
-    // Confirm we can find the added ones from the zone data.
-    checkFindRdataSet(zone_data_->getZoneTree(), a_rrset_->getName(),
-                      RRType::A(), rdataset_a);
-    checkFindRdataSet(zone_data_->getZoneTree(), a_rrset_->getName(),
-                      RRType::AAAA(), rdataset_aaaa);
-    // There's no NS (or anything other than AAAA or A) RdataSet in the list
-    checkFindRdataSet(zone_data_->getZoneTree(), a_rrset_->getName(),
-                      RRType::NS(), NULL);
-
-    // TearDown() will confirm there's no leak on destroy
-}
-
-TEST_F(ZoneDataTest, getSetNSEC3Data) {
-    // Initially there's no NSEC3 data
-    EXPECT_EQ(static_cast<NSEC3Data*>(NULL), zone_data_->getNSEC3Data());
-    // isNSEC3Signed is true iff zone data has non NULL NSEC3 data
-    EXPECT_FALSE(zone_data_->isNSEC3Signed());
-
-    // Set a new one.  The set method should return NULL.  The get method
-    // should return the new one.
-    NSEC3Data* nsec3_data = NSEC3Data::create(mem_sgmt_, param_rdata_);
-    NSEC3Data* old_nsec3_data = zone_data_->setNSEC3Data(nsec3_data);
-    EXPECT_EQ(static_cast<NSEC3Data*>(NULL), old_nsec3_data);
-    EXPECT_EQ(nsec3_data, zone_data_->getNSEC3Data());
-    EXPECT_TRUE(zone_data_->isNSEC3Signed());
-
-    // Replace an existing one with a yet another one.
-    // We're responsible for destroying the old one.
-    NSEC3Data* nsec3_data2 = NSEC3Data::create(mem_sgmt_, nsec3_rdata_);
-    old_nsec3_data = zone_data_->setNSEC3Data(nsec3_data2);
-    EXPECT_EQ(nsec3_data, old_nsec3_data);
-    EXPECT_EQ(nsec3_data2, zone_data_->getNSEC3Data());
-    EXPECT_TRUE(zone_data_->isNSEC3Signed());
-    NSEC3Data::destroy(mem_sgmt_, old_nsec3_data, RRClass::IN());
-
-    // Setting NULL clears any existing one.
-    old_nsec3_data = zone_data_->setNSEC3Data(NULL);
-    EXPECT_EQ(nsec3_data2, old_nsec3_data);
-    EXPECT_EQ(static_cast<NSEC3Data*>(NULL), zone_data_->getNSEC3Data());
-    EXPECT_FALSE(zone_data_->isNSEC3Signed());
-
-    // Then set it again.  The zone data should destroy it on its own
-    // destruction.
-    zone_data_->setNSEC3Data(old_nsec3_data);
-}
-
-TEST_F(ZoneDataTest, isSigned) {
-    // By default it's considered unsigned
-    EXPECT_FALSE(zone_data_->isSigned());
-
-    // declare it's signed, the isSigned() says so too
-    zone_data_->setSigned(true);
-    EXPECT_TRUE(zone_data_->isSigned());
-
-    // change it to unsigned again
-    zone_data_->setSigned(false);
-    EXPECT_FALSE(zone_data_->isSigned());
-}
-}
diff --git a/src/lib/datasrc/memory/tests/zone_finder_unittest.cc b/src/lib/datasrc/memory/tests/zone_finder_unittest.cc
deleted file mode 100644
index 94ebe5e..0000000
--- a/src/lib/datasrc/memory/tests/zone_finder_unittest.cc
+++ /dev/null
@@ -1,1481 +0,0 @@
-// 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 "memory_segment_test.h"
-
-// NOTE: this faked_nsec3 inclusion (and all related code below)
-// was ported during #2109 for the convenience of implementing #2218
-// In #2218 the NSEC3 test code in this file is expected to be finalized.
-// In #2219 the original is expected to be removed, and this file should
-// probably be moved here (and any leftover code not handled in #2218 should
-// be cleaned up)
-#include "../../tests/faked_nsec3.h"
-
-#include <datasrc/memory/zone_finder.h>
-#include <datasrc/memory/rdata_serialization.h>
-#include <datasrc/data_source.h>
-#include <testutils/dnsmessage_test.h>
-
-#include <boost/foreach.hpp>
-
-#include <gtest/gtest.h>
-
-using namespace std;
-using namespace isc::dns;
-using namespace isc::dns::rdata;
-using namespace isc::datasrc;
-using namespace isc::testutils;
-using boost::shared_ptr;
-using namespace isc::datasrc::test;
-using namespace isc::datasrc::memory::test;
-using namespace isc::datasrc::memory;
-
-namespace {
-// Commonly used result codes (Who should write the prefix all the time)
-using result::SUCCESS;
-using result::EXIST;
-
-// Some faked NSEC3 hash values commonly used in tests and the faked NSEC3Hash
-// object.
-//
-// For apex (example.org)
-const char* const apex_hash = "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
-const char* const apex_hash_lower = "0p9mhaveqvm6t7vbl5lop2u3t2rp3tom";
-// For ns1.example.org
-const char* const ns1_hash = "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR";
-// For w.example.org
-const char* const w_hash = "01UDEMVP1J2F7EG6JEBPS17VP3N8I58H";
-// For x.y.w.example.org (lower-cased)
-const char* const xyw_hash = "2vptu5timamqttgl4luu9kg21e0aor3s";
-// For zzz.example.org.
-const char* const zzz_hash = "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN";
-
-// A simple faked NSEC3 hash calculator with a dedicated creator for it.
-//
-// This is used in some NSEC3-related tests below.
-// Also see NOTE at inclusion of "../../tests/faked_nsec3.h"
-class TestNSEC3HashCreator : public NSEC3HashCreator {
-    class TestNSEC3Hash : public NSEC3Hash {
-    private:
-        typedef map<Name, string> NSEC3HashMap;
-        typedef NSEC3HashMap::value_type NSEC3HashPair;
-        NSEC3HashMap map_;
-    public:
-        TestNSEC3Hash() {
-            // Build pre-defined hash
-            map_[Name("example.org")] = apex_hash;
-            map_[Name("www.example.org")] = "2S9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
-            map_[Name("xxx.example.org")] = "Q09MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
-            map_[Name("yyy.example.org")] = "0A9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
-            map_[Name("x.y.w.example.org")] =
-                "2VPTU5TIMAMQTTGL4LUU9KG21E0AOR3S";
-            map_[Name("y.w.example.org")] = "K8UDEMVP1J2F7EG6JEBPS17VP3N8I58H";
-            map_[Name("w.example.org")] = w_hash;
-            map_[Name("zzz.example.org")] = zzz_hash;
-            map_[Name("smallest.example.org")] =
-                "00000000000000000000000000000000";
-            map_[Name("largest.example.org")] =
-                "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU";
-        }
-        virtual string calculate(const Name& name) const {
-            const NSEC3HashMap::const_iterator found = map_.find(name);
-            if (found != map_.end()) {
-                return (found->second);
-            }
-            isc_throw(isc::Unexpected, "unexpected name for NSEC3 test: "
-                      << name);
-        }
-        virtual bool match(const generic::NSEC3PARAM&) const {
-            return (true);
-        }
-        virtual bool match(const generic::NSEC3&) const {
-            return (true);
-        }
-    };
-
-public:
-    virtual NSEC3Hash* create(const generic::NSEC3PARAM&) const {
-        return (new TestNSEC3Hash);
-    }
-    virtual NSEC3Hash* create(const generic::NSEC3&) const {
-        return (new TestNSEC3Hash);
-    }
-};
-
-
-/// \brief expensive rrset converter
-///
-/// converts any specialized rrset (which may not have implemented some
-/// methods for efficiency) into a 'full' RRsetPtr, for easy use in test
-/// checks.
-///
-/// Done very inefficiently through text representation, speed should not
-/// be a concern here.
-ConstRRsetPtr
-convertRRset(ConstRRsetPtr src) {
-    return (textToRRset(src->toText()));
-}
-
-/// \brief Test fixture for the InMemoryZoneFinder class
-class InMemoryZoneFinderTest : public ::testing::Test {
-    // A straightforward pair of textual RR(set) and a RRsetPtr variable
-    // to store the RRset.  Used to build test data below.
-    struct RRsetData {
-        const char* const text; // textual representation of an RRset
-        RRsetPtr* rrset;
-    };
-protected:
-    // The following sub tests are shared by multiple test cases, changing
-    // the zone's DNSSEC status (unsigned, NSEC-signed or NSEC3-signed).
-    // expected_flags is set to either RESULT_NSEC_SIGNED or
-    // RESULT_NSEC3_SIGNED when it's NSEC/NSEC3 signed respectively and
-    // find() is expected to set the corresponding flags.
-    // find_options should be set to FIND_DNSSEC for NSEC-signed case when
-    // NSEC is expected to be returned.
-    void findCheck(ZoneFinder::FindResultFlags expected_flags =
-                   ZoneFinder::RESULT_DEFAULT,
-                   ZoneFinder::FindOptions find_options =
-                   ZoneFinder::FIND_DEFAULT);
-    void emptyNodeCheck(ZoneFinder::FindResultFlags expected_flags =
-                        ZoneFinder::RESULT_DEFAULT);
-    void wildcardCheck(ZoneFinder::FindResultFlags expected_flags =
-                       ZoneFinder::RESULT_DEFAULT,
-                       ZoneFinder::FindOptions find_options =
-                       ZoneFinder::FIND_DEFAULT);
-    void doCancelWildcardCheck(ZoneFinder::FindResultFlags expected_flags =
-                               ZoneFinder::RESULT_DEFAULT,
-                               ZoneFinder::FindOptions find_options =
-                               ZoneFinder::FIND_DEFAULT);
-    void anyWildcardCheck(ZoneFinder::FindResultFlags expected_flags =
-                          ZoneFinder::RESULT_DEFAULT);
-    void emptyWildcardCheck(ZoneFinder::FindResultFlags expected_flags =
-                            ZoneFinder::RESULT_DEFAULT);
-    void findNSECENTCheck(const Name& ent_name,
-                          ConstRRsetPtr expected_nsec,
-                          ZoneFinder::FindResultFlags expected_flags =
-                          ZoneFinder::RESULT_DEFAULT);
-
-public:
-    InMemoryZoneFinderTest() :
-        class_(RRClass::IN()),
-        origin_("example.org"),
-        zone_data_(ZoneData::create(mem_sgmt_, origin_)),
-        zone_finder_(*zone_data_, class_)
-    {
-        // Build test RRsets.  Below, we construct an RRset for
-        // each textual RR(s) of zone_data, and assign it to the corresponding
-        // rr_xxx.
-        // Note that this contains an out-of-zone RR, and due to the
-        // validation check of masterLoad() used below, we cannot add SOA.
-        const RRsetData zone_data[] = {
-            {"example.org. 300 IN NS ns.example.org.", &rr_ns_},
-            {"example.org. 300 IN A 192.0.2.1", &rr_a_},
-            {"ns.example.org. 300 IN A 192.0.2.2", &rr_ns_a_},
-            {"ns.example.org. 300 IN AAAA 2001:db8::2", &rr_ns_aaaa_},
-            {"cname.example.org. 300 IN CNAME canonical.example.org",
-             &rr_cname_},
-            {"cname.example.org. 300 IN A 192.0.2.3", &rr_cname_a_},
-            {"dname.example.org. 300 IN DNAME target.example.org.",
-             &rr_dname_},
-            {"dname.example.org. 300 IN A 192.0.2.39", &rr_dname_a_},
-            {"dname.example.org. 300 IN NS ns.dname.example.org.",
-             &rr_dname_ns_},
-            {"example.org. 300 IN DNAME example.com.", &rr_dname_apex_},
-            {"child.example.org. 300 IN NS ns.child.example.org.",
-             &rr_child_ns_},
-            {"child.example.org. 300 IN DS 12345 5 1 DEADBEEF",
-             &rr_child_ds_},
-            {"ns.child.example.org. 300 IN A 192.0.2.153",
-             &rr_child_glue_},
-            {"grand.child.example.org. 300 IN NS ns.grand.child.example.org.",
-             &rr_grandchild_ns_},
-            {"ns.grand.child.example.org. 300 IN AAAA 2001:db8::253",
-             &rr_grandchild_glue_},
-            {"dname.child.example.org. 300 IN DNAME example.com.",
-             &rr_child_dname_},
-            {"example.com. 300 IN A 192.0.2.10", &rr_out_},
-            {"*.wild.example.org. 300 IN A 192.0.2.1", &rr_wild_},
-            {"*.cnamewild.example.org. 300 IN CNAME canonial.example.org.",
-             &rr_cnamewild_},
-            {"foo.wild.example.org. 300 IN A 192.0.2.3", &rr_under_wild_},
-            {"wild.*.foo.example.org. 300 IN A 192.0.2.1", &rr_emptywild_},
-            {"wild.*.foo.*.bar.example.org. 300 IN A 192.0.2.1",
-             &rr_nested_emptywild_},
-            {"*.nswild.example.org. 300 IN NS nswild.example.", &rr_nswild_},
-            {"*.dnamewild.example.org. 300 IN DNAME dnamewild.example.",
-             &rr_dnamewild_},
-            {"*.child.example.org. 300 IN A 192.0.2.1", &rr_child_wild_},
-            {"bar.foo.wild.example.org. 300 IN A 192.0.2.2", &rr_not_wild_},
-            {"baz.foo.wild.example.org. 300 IN A 192.0.2.3",
-             &rr_not_wild_another_},
-            {"0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM.example.org. 300 IN "
-             "NSEC3 1 1 12 aabbccdd 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG",
-             &rr_nsec3_},
-            {"example.org. 300 IN NSEC wild.*.foo.example.org. "
-             "NS SOA RRSIG NSEC DNSKEY", &rr_nsec_},
-            // Together with the apex NSEC, these next NSECs make a complete
-            // chain in the case of the zone for the emptyNonterminal tests
-            // (We may want to clean up this generator code and/or masterLoad
-            // so that we can prepare conflicting datasets better)
-            {"wild.*.foo.example.org. 3600 IN NSEC ns.example.org. "
-             "A RRSIG NSEC", &rr_ent_nsec2_},
-            {"ns.example.org. 3600 IN NSEC foo.wild.example.org. A RRSIG NSEC",
-             &rr_ent_nsec3_},
-            {"foo.wild.example.org. 3600 IN NSEC example.org. A RRSIG NSEC",
-             &rr_ent_nsec4_},
-            // And these are NSECs used in different tests
-            {"ns.example.org. 300 IN NSEC *.nswild.example.org. A AAAA NSEC",
-             &rr_ns_nsec_},
-            {"*.wild.example.org. 300 IN NSEC foo.wild.example.org. A NSEC",
-             &rr_wild_nsec_},
-            {NULL, NULL}
-        };
-
-        for (unsigned int i = 0; zone_data[i].text != NULL; ++i) {
-            *zone_data[i].rrset = textToRRset(zone_data[i].text);
-        }
-
-    }
-
-    ~InMemoryZoneFinderTest() {
-        // Make sure we reset the hash creator to the default
-        setNSEC3HashCreator(NULL);
-        ZoneData::destroy(mem_sgmt_, zone_data_, RRClass::IN());
-    }
-
-    // NSEC3-specific call for 'loading' data
-    // This needs to be updated and checked when implementing #2118
-    void addZoneDataNSEC3(const ConstRRsetPtr rrset) {
-        assert(rrset->getType() == RRType::NSEC3());
-
-        const Rdata* rdata = &rrset->getRdataIterator()->getCurrent();
-        const generic::NSEC3* nsec3_rdata =
-            dynamic_cast<const generic::NSEC3*>(rdata);
-        NSEC3Data* nsec3_data = NSEC3Data::create(mem_sgmt_, *nsec3_rdata);
-        // in case we happen to be replacing, destroy old
-        NSEC3Data* old_data = zone_data_->setNSEC3Data(nsec3_data);
-        if (old_data != NULL) {
-            NSEC3Data::destroy(mem_sgmt_, old_data, rrset->getClass());
-        }
-        zone_data_->setSigned(true);
-    }
-
-    // simplified version of 'loading' data
-    void addZoneData(const ConstRRsetPtr rrset) {
-        ZoneNode* node = NULL;
-
-        if (rrset->getType() == RRType::NSEC3()) {
-            return (addZoneDataNSEC3(rrset));
-        } else if (rrset->getType() == RRType::NSEC()) {
-            zone_data_->setSigned(true);
-        }
-
-        zone_data_->insertName(mem_sgmt_, rrset->getName(), &node);
-
-        if (rrset->getType() == RRType::NS() &&
-            rrset->getName() != zone_data_->getOriginNode()->getName()) {
-            node->setFlag(DomainTreeNode<RdataSet>::FLAG_CALLBACK);
-        } else if (rrset->getType() == RRType::DNAME()) {
-            node->setFlag(DomainTreeNode<RdataSet>::FLAG_CALLBACK);
-        }
-
-        RdataSet* next_rds = node->getData();
-        RdataSet* rdataset =
-            RdataSet::create(mem_sgmt_, encoder_, rrset, rrset->getRRsig());
-        rdataset->next = next_rds;
-        node->setData(rdataset);
-
-        // find wildcard nodes in name (go through all of them in case there
-        // is a nonterminal one)
-        // Note that this method is pretty much equal to the 'real' loader;
-        // but less efficient
-        Name name(rrset->getName());
-        while (name.getLabelCount() > 1) {
-            if (name.isWildcard()) {
-                ZoneNode* wnode = NULL;
-                // add Wild node
-                zone_data_->insertName(mem_sgmt_, name.split(1), &wnode);
-                wnode->setFlag(ZoneData::WILDCARD_NODE);
-                // add wildcard name itself too
-                zone_data_->insertName(mem_sgmt_, name, &wnode);
-            }
-            name = name.split(1);
-        }
-    }
-
-    // Some data to test with
-    const RRClass class_;
-    const Name origin_;
-    // The zone finder to torture by tests
-    MemorySegmentTest mem_sgmt_;
-    memory::ZoneData* zone_data_;
-    memory::InMemoryZoneFinder zone_finder_;
-    isc::datasrc::memory::RdataEncoder encoder_;
-
-    // Placeholder for storing RRsets to be checked with rrsetsCheck()
-    vector<ConstRRsetPtr> actual_rrsets_;
-
-    /*
-     * Some RRsets to put inside the zone.
-     */
-    RRsetPtr
-        // Out of zone RRset
-        rr_out_,
-        // NS of example.org
-        rr_ns_,
-        // A of ns.example.org
-        rr_ns_a_,
-        // AAAA of ns.example.org
-        rr_ns_aaaa_,
-        // A of example.org
-        rr_a_;
-    RRsetPtr rr_cname_;         // CNAME in example.org (RDATA will be added)
-    RRsetPtr rr_cname_a_; // for mixed CNAME + A case
-    RRsetPtr rr_dname_;         // DNAME in example.org (RDATA will be added)
-    RRsetPtr rr_dname_a_; // for mixed DNAME + A case
-    RRsetPtr rr_dname_ns_; // for mixed DNAME + NS case
-    RRsetPtr rr_dname_apex_; // for mixed DNAME + NS case in the apex
-    RRsetPtr rr_child_ns_; // NS of a child domain (for delegation)
-    RRsetPtr rr_child_ds_; // DS of a child domain (for delegation, auth data)
-    RRsetPtr rr_child_glue_; // glue RR of the child domain
-    RRsetPtr rr_grandchild_ns_; // NS below a zone cut (unusual)
-    RRsetPtr rr_grandchild_glue_; // glue RR below a deeper zone cut
-    RRsetPtr rr_child_dname_; // A DNAME under NS
-    RRsetPtr rr_wild_;        // Wildcard record
-    RRsetPtr rr_cnamewild_;     // CNAME at a wildcard
-    RRsetPtr rr_emptywild_;
-    RRsetPtr rr_nested_emptywild_;
-    RRsetPtr rr_nswild_, rr_dnamewild_;
-    RRsetPtr rr_child_wild_;
-    RRsetPtr rr_under_wild_;
-    RRsetPtr rr_not_wild_;
-    RRsetPtr rr_not_wild_another_;
-    RRsetPtr rr_nsec3_;
-    RRsetPtr rr_nsec_;
-    RRsetPtr rr_ent_nsec2_;
-    RRsetPtr rr_ent_nsec3_;
-    RRsetPtr rr_ent_nsec4_;
-    RRsetPtr rr_ns_nsec_;
-    RRsetPtr rr_wild_nsec_;
-
-    // A faked NSEC3 hash calculator for convenience.
-    // Tests that need to use the faked hashed values should call
-    // setNSEC3HashCreator() with a pointer to this variable at the beginning
-    // of the test (at least before adding any NSEC3/NSEC3PARAM RR).
-    TestNSEC3HashCreator nsec3_hash_creator_;
-
-    /**
-     * \brief Test one find query to the zone finder.
-     *
-     * Asks a query to the zone finder and checks it does not throw and returns
-     * expected results. It returns nothing, it just signals failures
-     * to GTEST.
-     *
-     * \param name The name to ask for.
-     * \param rrtype The RRType to ask of.
-     * \param result The expected code of the result.
-     * \param check_answer Should a check against equality of the answer be
-     *     done?
-     * \param answer The expected rrset, if any should be returned.
-     * \param expected_flags The expected result flags returned via find().
-     *     These can be tested using isWildcard() etc.
-     * \param zone_finder Check different InMemoryZoneFinder object than
-     *     zone_finder_ (if NULL, uses zone_finder_)
-     * \param check_wild_answer Checks that the answer has the same RRs, type
-     *     class and TTL as the eqxpected answer and that the name corresponds
-     *     to the one searched. It is meant for checking answers for wildcard
-     *     queries.
-     */
-    void findTest(const Name& name, const RRType& rrtype,
-                  ZoneFinder::Result result,
-                  bool check_answer = true,
-                  const ConstRRsetPtr& answer = ConstRRsetPtr(),
-                  ZoneFinder::FindResultFlags expected_flags =
-                  ZoneFinder::RESULT_DEFAULT,
-                  memory::InMemoryZoneFinder* zone_finder = NULL,
-                  ZoneFinder::FindOptions options = ZoneFinder::FIND_DEFAULT,
-                  bool check_wild_answer = false)
-    {
-        SCOPED_TRACE("findTest for " + name.toText() + "/" + rrtype.toText());
-
-        if (zone_finder == NULL) {
-            zone_finder = &zone_finder_;
-        }
-        const ConstRRsetPtr answer_sig = answer ? answer->getRRsig() :
-            RRsetPtr(); // note we use the same type as of retval of getRRsig()
-        // The whole block is inside, because we need to check the result and
-        // we can't assign to FindResult
-        EXPECT_NO_THROW({
-                ZoneFinderContextPtr find_result(zone_finder->find(
-                                                     name, rrtype, options));
-                // Check it returns correct answers
-                EXPECT_EQ(result, find_result->code);
-                EXPECT_EQ((expected_flags & ZoneFinder::RESULT_WILDCARD) != 0,
-                          find_result->isWildcard());
-                EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED)
-                          != 0, find_result->isNSECSigned());
-                EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED)
-                          != 0, find_result->isNSEC3Signed());
-                if (check_answer) {
-                    if (!answer) {
-                        ASSERT_FALSE(find_result->rrset);
-                    } else {
-                        ASSERT_TRUE(find_result->rrset);
-                        ConstRRsetPtr result_rrset(
-                            convertRRset(find_result->rrset));
-                        rrsetCheck(answer, result_rrset);
-                        if (answer_sig) {
-                            ASSERT_TRUE(result_rrset->getRRsig());
-                            rrsetCheck(answer_sig, result_rrset->getRRsig());
-                        }
-                    }
-                } else if (check_wild_answer) {
-                    ASSERT_NE(ConstRRsetPtr(), answer) <<
-                        "Wrong test, don't check for wild names if you expect "
-                        "empty answer";
-                    ASSERT_NE(ConstRRsetPtr(), find_result->rrset) <<
-                        "No answer found";
-                    // Build the expected answer using the given name and
-                    // other parameter of the base wildcard RRset.
-                    RRsetPtr wildanswer(new RRset(name, answer->getClass(),
-                                                  answer->getType(),
-                                                  answer->getTTL()));
-                    RdataIteratorPtr expectedIt(answer->getRdataIterator());
-                    for (; !expectedIt->isLast(); expectedIt->next()) {
-                        wildanswer->addRdata(expectedIt->getCurrent());
-                    }
-
-                    ConstRRsetPtr result_rrset(
-                        convertRRset(find_result->rrset));
-                    rrsetCheck(wildanswer, result_rrset);
-
-                    // Same for the RRSIG, if any.
-                    if (answer_sig) {
-                        ASSERT_TRUE(result_rrset->getRRsig());
-
-                        RRsetPtr wildsig(new RRset(name,
-                                                   answer_sig->getClass(),
-                                                   RRType::RRSIG(),
-                                                   answer_sig->getTTL()));
-                        RdataIteratorPtr expectedIt(
-                            answer_sig->getRdataIterator());
-                        for (; !expectedIt->isLast(); expectedIt->next()) {
-                            wildsig->addRdata(expectedIt->getCurrent());
-                        }
-                        rrsetCheck(wildsig, result_rrset->getRRsig());
-                    }
-                }
-            });
-    }
-    /**
-     * \brief Calls the findAll on the finder and checks the result.
-     */
-    void findAllTest(const Name& name, ZoneFinder::Result result,
-                     const vector<ConstRRsetPtr>& expected_rrsets,
-                     ZoneFinder::FindResultFlags expected_flags =
-                     ZoneFinder::RESULT_DEFAULT,
-                     memory::InMemoryZoneFinder* finder = NULL,
-                     const ConstRRsetPtr &rrset_result = ConstRRsetPtr(),
-                     ZoneFinder::FindOptions options =
-                     ZoneFinder::FIND_DEFAULT)
-    {
-        if (finder == NULL) {
-            finder = &zone_finder_;
-        }
-        std::vector<ConstRRsetPtr> target;
-        ZoneFinderContextPtr find_result(finder->findAll(name, target,
-                                                         options));
-        EXPECT_EQ(result, find_result->code);
-        if (!rrset_result) {
-            EXPECT_FALSE(find_result->rrset);
-        } else {
-            ASSERT_TRUE(find_result->rrset);
-            rrsetCheck(rrset_result, convertRRset(find_result->rrset));
-        }
-        EXPECT_EQ((expected_flags & ZoneFinder::RESULT_WILDCARD) != 0,
-                  find_result->isWildcard());
-        EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED)
-                  != 0, find_result->isNSECSigned());
-        EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED)
-                  != 0, find_result->isNSEC3Signed());
-        // Convert all rrsets to 'full' ones before checking
-        std::vector<ConstRRsetPtr> converted_rrsets;
-        BOOST_FOREACH(ConstRRsetPtr cur_rrset, target) {
-            converted_rrsets.push_back(convertRRset(cur_rrset));
-        }
-        rrsetsCheck(expected_rrsets.begin(), expected_rrsets.end(),
-                    converted_rrsets.begin(), converted_rrsets.end());
-    }
-};
-
-/**
- * \brief Test InMemoryZoneFinder::InMemoryZoneFinder constructor.
- *
- * Takes the created zone finder and checks its properties they are the same
- * as passed parameters.
- */
-TEST_F(InMemoryZoneFinderTest, constructor) {
-    ASSERT_EQ(origin_, zone_finder_.getOrigin());
-}
-
-TEST_F(InMemoryZoneFinderTest, findCNAME) {
-    // install CNAME RR
-    addZoneData(rr_cname_);
-
-    // Find A RR of the same.  Should match the CNAME
-    findTest(rr_cname_->getName(), RRType::NS(), ZoneFinder::CNAME, true,
-             rr_cname_);
-
-    // Find the CNAME itself.  Should result in normal SUCCESS
-    findTest(rr_cname_->getName(), RRType::CNAME(), ZoneFinder::SUCCESS, true,
-             rr_cname_);
-}
-
-TEST_F(InMemoryZoneFinderTest, findCNAMEUnderZoneCut) {
-    // There's nothing special when we find a CNAME under a zone cut
-    // (with FIND_GLUE_OK).  The behavior is different from BIND 9,
-    // so we test this case explicitly.
-    addZoneData(rr_child_ns_);
-    ConstRRsetPtr rr_cname_under_cut_ = textToRRset(
-        "cname.child.example.org. 300 IN CNAME target.child.example.org.");
-    addZoneData(rr_cname_under_cut_);
-    findTest(Name("cname.child.example.org"), RRType::AAAA(),
-             ZoneFinder::CNAME, true, rr_cname_under_cut_,
-             ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
-}
-
-// Search under a DNAME record. It should return the DNAME
-TEST_F(InMemoryZoneFinderTest, findBelowDNAME) {
-    EXPECT_NO_THROW(addZoneData(rr_dname_));
-    findTest(Name("below.dname.example.org"), RRType::A(), ZoneFinder::DNAME,
-             true, rr_dname_);
-}
-
-// Search at the domain with DNAME. It should act as DNAME isn't there, DNAME
-// influences only the data below (see RFC 2672, section 3)
-TEST_F(InMemoryZoneFinderTest, findAtDNAME) {
-    EXPECT_NO_THROW(addZoneData(rr_dname_));
-    EXPECT_NO_THROW(addZoneData(rr_dname_a_));
-
-    const Name dname_name(rr_dname_->getName());
-    findTest(dname_name, RRType::A(), ZoneFinder::SUCCESS, true, rr_dname_a_);
-    findTest(dname_name, RRType::DNAME(), ZoneFinder::SUCCESS, true,
-             rr_dname_);
-    findTest(dname_name, RRType::TXT(), ZoneFinder::NXRRSET, true);
-}
-
-// Try searching something that is both under NS and DNAME, without and with
-// GLUE_OK mode (it should stop at the NS and DNAME respectively).
-TEST_F(InMemoryZoneFinderTest, DNAMEUnderNS) {
-    addZoneData(rr_child_ns_);
-    addZoneData(rr_child_dname_);
-
-    Name lowName("below.dname.child.example.org.");
-
-    findTest(lowName, RRType::A(), ZoneFinder::DELEGATION, true, rr_child_ns_);
-    findTest(lowName, RRType::A(), ZoneFinder::DNAME, true, rr_child_dname_,
-             ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
-}
-
-// Test adding child zones and zone cut handling
-TEST_F(InMemoryZoneFinderTest, delegationNS) {
-    // add in-zone data
-    EXPECT_NO_THROW(addZoneData(rr_ns_));
-
-    // install a zone cut
-    EXPECT_NO_THROW(addZoneData(rr_child_ns_));
-
-    // below the zone cut
-    findTest(Name("www.child.example.org"), RRType::A(),
-             ZoneFinder::DELEGATION, true, rr_child_ns_);
-
-    // at the zone cut
-    findTest(Name("child.example.org"), RRType::A(), ZoneFinder::DELEGATION,
-             true, rr_child_ns_);
-    findTest(Name("child.example.org"), RRType::NS(), ZoneFinder::DELEGATION,
-             true, rr_child_ns_);
-
-    // finding NS for the apex (origin) node.  This must not be confused
-    // with delegation due to the existence of an NS RR.
-    findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
-
-    // unusual case of "nested delegation": the highest cut should be used.
-    EXPECT_NO_THROW(addZoneData(rr_grandchild_ns_));
-    findTest(Name("www.grand.child.example.org"), RRType::A(),
-             // note: !rr_grandchild_ns_
-             ZoneFinder::DELEGATION, true, rr_child_ns_);
-}
-
-TEST_F(InMemoryZoneFinderTest, delegationWithDS) {
-    // Similar setup to the previous one, but with DS RR at the delegation
-    // point.
-    addZoneData(rr_ns_);
-    addZoneData(rr_child_ns_);
-    addZoneData(rr_child_ds_);
-
-    // Normal types of query should result in delegation, but DS query
-    // should be considered in-zone (but only exactly at the delegation point).
-    findTest(Name("child.example.org"), RRType::A(), ZoneFinder::DELEGATION,
-             true, rr_child_ns_);
-    findTest(Name("child.example.org"), RRType::DS(), ZoneFinder::SUCCESS,
-             true, rr_child_ds_);
-    findTest(Name("grand.child.example.org"), RRType::DS(),
-             ZoneFinder::DELEGATION, true, rr_child_ns_);
-
-    // There's nothing special for DS query at the zone apex.  It would
-    // normally result in NXRRSET.
-    findTest(Name("example.org"), RRType::DS(), ZoneFinder::NXRRSET,
-             true, ConstRRsetPtr());
-}
-
-TEST_F(InMemoryZoneFinderTest, findAny) {
-    EXPECT_NO_THROW(addZoneData(rr_a_));
-    EXPECT_NO_THROW(addZoneData(rr_ns_));
-    EXPECT_NO_THROW(addZoneData(rr_child_glue_));
-
-    vector<ConstRRsetPtr> expected_sets;
-
-    // origin
-    expected_sets.push_back(rr_a_);
-    expected_sets.push_back(rr_ns_);
-    findAllTest(origin_, ZoneFinder::SUCCESS, expected_sets);
-
-    // out zone name
-    EXPECT_THROW(findAllTest(Name("example.com"), ZoneFinder::NXDOMAIN,
-                             vector<ConstRRsetPtr>()),
-                 OutOfZone);
-
-    expected_sets.clear();
-    expected_sets.push_back(rr_child_glue_);
-    findAllTest(rr_child_glue_->getName(), ZoneFinder::SUCCESS, expected_sets);
-
-    // add zone cut
-    EXPECT_NO_THROW(addZoneData(rr_child_ns_));
-
-    // zone cut
-    findAllTest(rr_child_ns_->getName(), ZoneFinder::DELEGATION,
-                vector<ConstRRsetPtr>(), ZoneFinder::RESULT_DEFAULT,
-                NULL, rr_child_ns_);
-
-    // glue for this zone cut
-    findAllTest(rr_child_glue_->getName(),ZoneFinder::DELEGATION,
-                vector<ConstRRsetPtr>(), ZoneFinder::RESULT_DEFAULT,
-                NULL, rr_child_ns_);
-}
-
-TEST_F(InMemoryZoneFinderTest, glue) {
-    // install zone data:
-    // a zone cut
-    EXPECT_NO_THROW(addZoneData(rr_child_ns_));
-    // glue for this cut
-    EXPECT_NO_THROW(addZoneData(rr_child_glue_));
-    // a nested zone cut (unusual)
-    EXPECT_NO_THROW(addZoneData(rr_grandchild_ns_));
-    // glue under the deeper zone cut
-    EXPECT_NO_THROW(addZoneData(rr_grandchild_glue_));
-
-    // by default glue is hidden due to the zone cut
-    findTest(rr_child_glue_->getName(), RRType::A(), ZoneFinder::DELEGATION,
-             true, rr_child_ns_);
-
-
-    // If we do it in the "glue OK" mode, we should find the exact match.
-    findTest(rr_child_glue_->getName(), RRType::A(), ZoneFinder::SUCCESS, true,
-             rr_child_glue_, ZoneFinder::RESULT_DEFAULT, NULL,
-             ZoneFinder::FIND_GLUE_OK);
-
-    // glue OK + NXRRSET case
-    findTest(rr_child_glue_->getName(), RRType::AAAA(), ZoneFinder::NXRRSET,
-             true, ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, NULL,
-             ZoneFinder::FIND_GLUE_OK);
-
-    // glue OK + NXDOMAIN case
-    findTest(Name("www.child.example.org"), RRType::A(),
-             ZoneFinder::DELEGATION, true, rr_child_ns_,
-             ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
-
-    // nested cut case.  The glue should be found.
-    findTest(rr_grandchild_glue_->getName(), RRType::AAAA(),
-             ZoneFinder::SUCCESS,
-             true, rr_grandchild_glue_, ZoneFinder::RESULT_DEFAULT, NULL,
-             ZoneFinder::FIND_GLUE_OK);
-
-    // A non-existent name in nested cut.  This should result in delegation
-    // at the highest zone cut.
-    findTest(Name("www.grand.child.example.org"), RRType::TXT(),
-             ZoneFinder::DELEGATION, true, rr_child_ns_,
-             ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
-}
-
-/**
- * \brief Test searching.
- *
- * Check it finds or does not find correctly and does not throw exceptions.
- */
-void
-InMemoryZoneFinderTest::findCheck(ZoneFinder::FindResultFlags expected_flags,
-                                  ZoneFinder::FindOptions find_options)
-{
-    // Fill some data inside
-    // Now put all the data we have there. It should throw nothing
-    EXPECT_NO_THROW(addZoneData(rr_ns_));
-    EXPECT_NO_THROW(addZoneData(rr_ns_a_));
-    EXPECT_NO_THROW(addZoneData(rr_ns_aaaa_));
-    EXPECT_NO_THROW(addZoneData(rr_a_));
-    if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
-        addZoneData(rr_nsec3_);
-        zone_data_->setSigned(true);
-    }
-    if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
-        addZoneData(rr_nsec_);
-        zone_data_->setSigned(true);
-    }
-
-    // These two should be successful
-    findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
-    findTest(rr_ns_a_->getName(), RRType::A(), ZoneFinder::SUCCESS, true,
-             rr_ns_a_);
-
-    // These domains don't exist. (and one is out of the zone).  In an
-    // NSEC-signed zone with DNSSEC records requested, it should return the
-    // covering NSEC for the query name (the actual NSEC in the test data may
-    // not really "cover" it, but for the purpose of this test it's okay).
-    ConstRRsetPtr expected_nsec; // by default it's NULL
-    if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0 &&
-        (find_options & ZoneFinder::FIND_DNSSEC) != 0) {
-        expected_nsec = rr_nsec_;
-    }
-
-    // There's no other name between this one and the origin, so when NSEC
-    // is to be returned it should be the origin NSEC.
-    findTest(Name("nothere.example.org"), RRType::A(),
-             ZoneFinder::NXDOMAIN, true, expected_nsec, expected_flags,
-             NULL, find_options);
-
-    // The previous name in the zone is "ns.example.org", but it doesn't
-    // have an NSEC.  It should be skipped and the origin NSEC will be
-    // returned as the "closest NSEC".
-    findTest(Name("nxdomain.example.org"), RRType::A(),
-             ZoneFinder::NXDOMAIN, true, expected_nsec, expected_flags,
-             NULL, find_options);
-    EXPECT_THROW(zone_finder_.find(Name("example.net"), RRType::A()),
-                 OutOfZone);
-
-    // These domain exist but don't have the provided RRType.  For the latter
-    // one we now add its NSEC (which was delayed so that it wouldn't break
-    // other cases above).
-    findTest(origin_, RRType::AAAA(), ZoneFinder::NXRRSET, true,
-             expected_nsec, expected_flags, NULL, find_options);
-
-    if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
-        addZoneData(rr_ns_nsec_);
-        zone_data_->setSigned(true);
-        if ((find_options & ZoneFinder::FIND_DNSSEC) != 0) {
-            expected_nsec = rr_ns_nsec_;
-        }
-    }
-    findTest(rr_ns_a_->getName(), RRType::NS(), ZoneFinder::NXRRSET, true,
-             expected_nsec, expected_flags, NULL, find_options);
-}
-
-TEST_F(InMemoryZoneFinderTest, find) {
-    findCheck();
-}
-
-TEST_F(InMemoryZoneFinderTest, findNSEC3Signed) {
-    findCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
-}
-
-TEST_F(InMemoryZoneFinderTest, findNSEC3SignedWithDNSSEC) {
-    // For NSEC3-signed zones, specifying the DNSSEC option shouldn't change
-    // anything (the NSEC3_SIGNED flag is always set, and no records are
-    // returned for negative cases regardless).
-    findCheck(ZoneFinder::RESULT_NSEC3_SIGNED, ZoneFinder::FIND_DNSSEC);
-}
-
-TEST_F(InMemoryZoneFinderTest, findNSECSigned) {
-    // NSEC-signed zone, without requesting DNSSEC (no NSEC should be provided)
-    findCheck(ZoneFinder::RESULT_NSEC_SIGNED);
-}
-
-// Generalized test for Empty Nonterminal (ENT) cases with NSEC
-void
-InMemoryZoneFinderTest::findNSECENTCheck(const Name& ent_name,
-    ConstRRsetPtr expected_nsec,
-    ZoneFinder::FindResultFlags expected_flags)
-{
-    addZoneData(rr_emptywild_);
-    addZoneData(rr_under_wild_);
-
-    // Sanity check: Should result in NXRRSET
-    findTest(ent_name, RRType::A(), ZoneFinder::NXRRSET, true,
-             ConstRRsetPtr(), expected_flags);
-    // Sanity check: No NSEC added yet
-    findTest(ent_name, RRType::A(), ZoneFinder::NXRRSET, true,
-             ConstRRsetPtr(), expected_flags,
-             NULL, ZoneFinder::FIND_DNSSEC);
-
-    // Now add the NSEC rrs making it a 'complete' zone (in terms of NSEC,
-    // there are no sigs)
-    addZoneData(rr_nsec_);
-    addZoneData(rr_ent_nsec2_);
-    addZoneData(rr_ent_nsec3_);
-    addZoneData(rr_ent_nsec4_);
-    zone_data_->setSigned(true);
-
-    // Should result in NXRRSET, and RESULT_NSEC_SIGNED
-    findTest(ent_name, RRType::A(), ZoneFinder::NXRRSET, true,
-             ConstRRsetPtr(),
-             expected_flags | ZoneFinder::RESULT_NSEC_SIGNED);
-
-    // And check for the NSEC if DNSSEC_OK
-    findTest(ent_name, RRType::A(), ZoneFinder::NXRRSET, true,
-             expected_nsec, expected_flags | ZoneFinder::RESULT_NSEC_SIGNED,
-             NULL, ZoneFinder::FIND_DNSSEC);
-}
-
-TEST_F(InMemoryZoneFinderTest,findNSECEmptyNonterminal) {
-    // Non-wildcard case
-    findNSECENTCheck(Name("wild.example.org"), rr_ent_nsec3_);
-}
-
-TEST_F(InMemoryZoneFinderTest, findNSECEmptyNonterminalWildcard) {
-    // Wildcard case, above actual wildcard
-    findNSECENTCheck(Name("foo.example.org"), rr_nsec_);
-}
-
-TEST_F(InMemoryZoneFinderTest, findNSECEmptyNonterminalAtWildcard) {
-    // Wildcard case, at actual wildcard
-    findNSECENTCheck(Name("bar.foo.example.org"), rr_nsec_,
-                     ZoneFinder::RESULT_WILDCARD);
-}
-
-TEST_F(InMemoryZoneFinderTest, findNSECSignedWithDNSSEC) {
-    // NSEC-signed zone, requesting DNSSEC (NSEC should be provided)
-    findCheck(ZoneFinder::RESULT_NSEC_SIGNED, ZoneFinder::FIND_DNSSEC);
-}
-
-void
-InMemoryZoneFinderTest::emptyNodeCheck(
-    ZoneFinder::FindResultFlags expected_flags)
-{
-    /*
-     * The backend RBTree for this test should look like as follows:
-     *          example.org
-     *               |
-     *              baz (empty; easy case)
-     *            /  |  \
-     *          bar  |  x.foo ('foo' part is empty; a bit trickier)
-     *              bbb
-     *             /
-     *           aaa
-     */
-
-    // Construct the test zone
-    const char* const names[] = {
-        "bar.example.org.", "x.foo.example.org.", "aaa.baz.example.org.",
-        "bbb.baz.example.org.", NULL};
-    for (int i = 0; names[i] != NULL; ++i) {
-        ConstRRsetPtr rrset = textToRRset(string(names[i]) +
-                                          " 300 IN A 192.0.2.1");
-        addZoneData(rrset);
-    }
-    if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
-        addZoneData(rr_nsec3_);
-        zone_data_->setSigned(true);
-    }
-    if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
-        addZoneData(rr_nsec_);
-        zone_data_->setSigned(true);
-    }
-
-    // empty node matching, easy case: the node for 'baz' exists with
-    // no data.
-    findTest(Name("baz.example.org"), RRType::A(), ZoneFinder::NXRRSET, true,
-             ConstRRsetPtr(), expected_flags);
-
-    // empty node matching, a trickier case: the node for 'foo' is part of
-    // "x.foo", which should be considered an empty node.
-    findTest(Name("foo.example.org"), RRType::A(), ZoneFinder::NXRRSET, true,
-             ConstRRsetPtr(), expected_flags);
-
-    // "org" is contained in "example.org", but it shouldn't be treated as
-    // NXRRSET because it's out of zone.
-    // Note: basically we don't expect such a query to be performed (the common
-    // operation is to identify the best matching zone first then perform
-    // search it), but we shouldn't be confused even in the unexpected case.
-    EXPECT_THROW(zone_finder_.find(Name("org"), RRType::A()), OutOfZone);
-}
-
-TEST_F(InMemoryZoneFinderTest, emptyNode) {
-    emptyNodeCheck();
-}
-
-TEST_F(InMemoryZoneFinderTest, emptyNodeNSEC3) {
-    emptyNodeCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
-}
-
-TEST_F(InMemoryZoneFinderTest, emptyNodeNSEC) {
-    emptyNodeCheck(ZoneFinder::RESULT_NSEC_SIGNED);
-}
-
-/*
- * Test that puts a (simple) wildcard into the zone and checks we can
- * correctly find the data.
- */
-void
-InMemoryZoneFinderTest::wildcardCheck(
-    ZoneFinder::FindResultFlags expected_flags,
-    ZoneFinder::FindOptions find_options)
-{
-    /*
-     *            example.org.
-     *                 |
-     *             [cname]wild (not *.wild, should have wild mark)
-     *                 |
-     *                 *
-     */
-
-    // If the zone is "signed" (detecting it by the NSEC/NSEC3 signed flags),
-    // add RRSIGs to the records.
-    if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0 ||
-        (expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
-        // Convenience shortcut.  The RDATA is not really validatable, but
-        // it doesn't matter for our tests.
-        const char* const rrsig_common = "5 3 3600 "
-            "20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE";
-
-        find_options = find_options | ZoneFinder::FIND_DNSSEC;
-        rr_wild_->addRRsig(textToRRset("*.wild.example.org. 300 IN RRSIG A " +
-                                       string(rrsig_common)));
-        rr_cnamewild_->addRRsig(textToRRset("*.cnamewild.example.org. 300 IN "
-                                            "RRSIG CNAME " +
-                                            string(rrsig_common)));
-    }
-    addZoneData(rr_wild_);
-    addZoneData(rr_cnamewild_);
-    // If the zone is expected to be "signed" with NSEC3, add an NSEC3.
-    // (the content of the NSEC3 shouldn't matter)
-    if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
-        addZoneData(rr_nsec3_);
-    }
-    if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
-        addZoneData(rr_nsec_);
-    }
-
-    // Search at the parent. The parent will not have the A, but it will
-    // be in the wildcard (so check the wildcard isn't matched at the parent)
-    {
-        SCOPED_TRACE("Search at parent");
-        if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
-            findTest(Name("wild.example.org"), RRType::A(),
-                     ZoneFinder::NXRRSET, true, rr_nsec_, expected_flags,
-                     NULL, find_options);
-        } else {
-            findTest(Name("wild.example.org"), RRType::A(),
-                     ZoneFinder::NXRRSET, true, ConstRRsetPtr(),
-                     expected_flags, NULL, find_options);
-        }
-    }
-
-    // For the test setup of "NSEC-signed" zone, we might expect it will
-    // be returned with a negative result, either because wildcard match is
-    // disabled by the search option or because wildcard match is canceled
-    // per protocol.
-    ConstRRsetPtr expected_nsec; // by default it's NULL
-    if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0 &&
-        (find_options & ZoneFinder::FIND_DNSSEC) != 0) {
-        expected_nsec = rr_nsec_;
-    }
-    // Explicitly converting the following to const pointers; some compilers
-    // would complain about mixed use of const and non const in ?: below.
-    const ConstRRsetPtr rr_wild = rr_wild_;
-    const ConstRRsetPtr rr_cnamewild = rr_cnamewild_;
-
-    // Search the original name of wildcard
-    {
-        SCOPED_TRACE("Search directly at *");
-        findTest(Name("*.wild.example.org"), RRType::A(), ZoneFinder::SUCCESS,
-                 true, rr_wild_, ZoneFinder::RESULT_DEFAULT, NULL,
-                 find_options);
-    }
-
-    // Below some of the test cases will normally result in a wildcard match;
-    // if NO_WILDCARD is specified, it should result in NXDOMAIN instead,
-    // and, when available and requested, the covering NSEC will be returned.
-    // The following are shortcut parameters to unify these cases.
-    const bool wild_ok = ((find_options & ZoneFinder::NO_WILDCARD) == 0);
-    const ZoneFinder::FindResultFlags wild_expected_flags =
-        wild_ok ? (ZoneFinder::RESULT_WILDCARD | expected_flags) :
-        expected_flags;
-
-    // Search "created" name.
-    {
-        SCOPED_TRACE("Search at created child");
-        findTest(Name("a.wild.example.org"), RRType::A(),
-                 wild_ok ? ZoneFinder::SUCCESS : ZoneFinder::NXDOMAIN, false,
-                 wild_ok ? rr_wild : expected_nsec,
-                 wild_expected_flags, NULL, find_options, wild_ok);
-    }
-
-    // Search name that has CNAME.
-    {
-        SCOPED_TRACE("Matching CNAME");
-        findTest(Name("a.cnamewild.example.org"), RRType::A(),
-                 wild_ok ? ZoneFinder::CNAME : ZoneFinder::NXDOMAIN, false,
-                 wild_ok ? rr_cnamewild : expected_nsec,
-                 wild_expected_flags, NULL, find_options, wild_ok);
-    }
-
-    // Search another created name, this time little bit lower
-    {
-        SCOPED_TRACE("Search at created grand-child");
-        findTest(Name("a.b.wild.example.org"), RRType::A(),
-                 wild_ok ? ZoneFinder::SUCCESS : ZoneFinder::NXDOMAIN, false,
-                 wild_ok ? rr_wild : expected_nsec,
-                 wild_expected_flags, NULL, find_options, wild_ok);
-    }
-
-    addZoneData(rr_under_wild_);
-    {
-        SCOPED_TRACE("Search under non-wildcard");
-        findTest(Name("bar.foo.wild.example.org"), RRType::A(),
-                 ZoneFinder::NXDOMAIN, true, expected_nsec, expected_flags,
-                 NULL, find_options);
-    }
-
-    // Wildcard match, but no data.  We add the additional NSEC at the wildcard
-    // at this point so that it wouldn't break other tests above.  Note also
-    // that in the NO_WILDCARD case the resulting NSEC is the same.  Ideally
-    // we could use a more tricky setup so we can distinguish these cases,
-    // but for this purpose it's not bad; what we'd like to test here is that
-    // wildcard substitution doesn't happen for either case, and the
-    // NO_WILDCARD effect itself can be checked by the result code (NXDOMAIN).
-    ConstRRsetPtr expected_wild_nsec; // by default it's NULL
-    if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
-        addZoneData(rr_wild_nsec_);
-        expected_wild_nsec = rr_wild_nsec_;
-    }
-    {
-        SCOPED_TRACE("Search at wildcard, no data");
-        findTest(Name("a.wild.example.org"), RRType::AAAA(),
-                 wild_ok ? ZoneFinder::NXRRSET : ZoneFinder::NXDOMAIN, true,
-                 wild_ok ? expected_wild_nsec : expected_wild_nsec,
-                 wild_expected_flags, NULL, find_options);
-    }
-}
-
-TEST_F(InMemoryZoneFinderTest, wildcard) {
-    // Normal case
-    wildcardCheck();
-}
-
-TEST_F(InMemoryZoneFinderTest, wildcardDisabledWithNSEC) {
-    // Wildcard is disabled.  In practice, this is used as part of query
-    // processing for an NSEC-signed zone, so we test that case specifically.
-    wildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED, ZoneFinder::NO_WILDCARD);
-}
-
-TEST_F(InMemoryZoneFinderTest, wildcardDisabledWithoutNSEC) {
-    // Similar to the previous once, but check the behavior for a non signed
-    // zone just in case.
-    wildcardCheck(ZoneFinder::RESULT_DEFAULT, ZoneFinder::NO_WILDCARD);
-}
-
-/*
- * Test that we don't match a wildcard if we get under delegation.
- * By 4.3.3 of RFC1034:
- * "Wildcard RRs do not apply:
- *   - When the query is in another zone.  That is, delegation cancels
- *     the wildcard defaults."
- */
-TEST_F(InMemoryZoneFinderTest, delegatedWildcard) {
-    addZoneData(rr_child_wild_);
-    addZoneData(rr_child_ns_);
-
-    {
-        SCOPED_TRACE("Looking under delegation point");
-        findTest(Name("a.child.example.org"), RRType::A(),
-                 ZoneFinder::DELEGATION, true, rr_child_ns_);
-    }
-
-    {
-        SCOPED_TRACE("Looking under delegation point in GLUE_OK mode");
-        findTest(Name("a.child.example.org"), RRType::A(),
-                 ZoneFinder::DELEGATION, true, rr_child_ns_,
-                 ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
-    }
-}
-
-// Tests combination of wildcard and ANY.
-void
-InMemoryZoneFinderTest::anyWildcardCheck(
-    ZoneFinder::FindResultFlags expected_flags)
-{
-    addZoneData(rr_wild_);
-    if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
-        addZoneData(rr_nsec3_);
-    }
-    if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
-        addZoneData(rr_nsec_);
-    }
-
-    vector<ConstRRsetPtr> expected_sets;
-
-    // First try directly the name (normal match)
-    {
-        SCOPED_TRACE("Asking directly for *");
-        expected_sets.push_back(rr_wild_);
-        findAllTest(Name("*.wild.example.org"), ZoneFinder::SUCCESS,
-                    expected_sets);
-    }
-
-    // Then a wildcard match
-    {
-        SCOPED_TRACE("Asking in the wild way");
-        expected_sets.clear();
-        RRsetPtr expected(new RRset(Name("a.wild.example.org"),
-                                    rr_wild_->getClass(), rr_wild_->getType(),
-                                    rr_wild_->getTTL()));
-        expected->addRdata(rr_wild_->getRdataIterator()->getCurrent());
-        expected_sets.push_back(expected);
-        findAllTest(Name("a.wild.example.org"), ZoneFinder::SUCCESS,
-                    expected_sets,
-                    ZoneFinder::RESULT_WILDCARD | expected_flags);
-    }
-}
-
-TEST_F(InMemoryZoneFinderTest, anyWildcard) {
-    anyWildcardCheck();
-}
-
-TEST_F(InMemoryZoneFinderTest, anyWildcardNSEC3) {
-    anyWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
-}
-
-TEST_F(InMemoryZoneFinderTest, anyWildcardNSEC) {
-    anyWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED);
-}
-
-// Test there's nothing in the wildcard in the middle if we load
-// wild.*.foo.example.org.
-void
-InMemoryZoneFinderTest::emptyWildcardCheck(
-    ZoneFinder::FindResultFlags expected_flags)
-{
-    /*
-     *            example.org.
-     *                foo
-     *                 *
-     *               wild
-     */
-    addZoneData(rr_emptywild_);
-    if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
-        addZoneData(rr_nsec3_);
-    }
-    if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
-        addZoneData(rr_nsec_);
-    }
-
-    {
-        SCOPED_TRACE("Asking for the original record under wildcard");
-        findTest(Name("wild.*.foo.example.org"), RRType::A(),
-                 ZoneFinder::SUCCESS, true, rr_emptywild_);
-    }
-
-    {
-        SCOPED_TRACE("Asking for A record");
-        findTest(Name("a.foo.example.org"), RRType::A(), ZoneFinder::NXRRSET,
-                 true, ConstRRsetPtr(),
-                 ZoneFinder::RESULT_WILDCARD | expected_flags);
-        findTest(Name("*.foo.example.org"), RRType::A(), ZoneFinder::NXRRSET,
-                 true, ConstRRsetPtr(), expected_flags);
-        findTest(Name("foo.example.org"), RRType::A(), ZoneFinder::NXRRSET,
-                 true, ConstRRsetPtr(), expected_flags);
-    }
-
-    {
-        SCOPED_TRACE("Asking for ANY record");
-        findAllTest(Name("*.foo.example.org"), ZoneFinder::NXRRSET,
-                    vector<ConstRRsetPtr>(), expected_flags);
-
-        findAllTest(Name("a.foo.example.org"), ZoneFinder::NXRRSET,
-                    vector<ConstRRsetPtr>(),
-                    ZoneFinder::RESULT_WILDCARD | expected_flags);
-    }
-
-    {
-        SCOPED_TRACE("Asking on the non-terminal");
-        findTest(Name("wild.bar.foo.example.org"), RRType::A(),
-                 ZoneFinder::NXRRSET, true, ConstRRsetPtr(),
-                 ZoneFinder::RESULT_WILDCARD | expected_flags);
-    }
-}
-
-TEST_F(InMemoryZoneFinderTest, emptyWildcard) {
-    emptyWildcardCheck();
-}
-
-TEST_F(InMemoryZoneFinderTest, emptyWildcardNSEC3) {
-    emptyWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
-}
-
-TEST_F(InMemoryZoneFinderTest, emptyWildcardNSEC) {
-    emptyWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED);
-}
-
-// Same as emptyWildcard, but with multiple * in the path.
-TEST_F(InMemoryZoneFinderTest, nestedEmptyWildcard) {
-    addZoneData(rr_nested_emptywild_);
-
-    {
-        SCOPED_TRACE("Asking for the original record under wildcards");
-        findTest(Name("wild.*.foo.*.bar.example.org"), RRType::A(),
-            ZoneFinder::SUCCESS, true, rr_nested_emptywild_);
-    }
-
-    {
-        SCOPED_TRACE("Matching wildcard against empty nonterminal");
-
-        const char* names[] = {
-            "baz.foo.*.bar.example.org",
-            "baz.foo.baz.bar.example.org",
-            "*.foo.baz.bar.example.org",
-            NULL
-        };
-
-        for (const char** name = names; *name != NULL; ++ name) {
-            SCOPED_TRACE(string("Node ") + *name);
-            findTest(Name(*name), RRType::A(), ZoneFinder::NXRRSET, true,
-                     ConstRRsetPtr(), ZoneFinder::RESULT_WILDCARD);
-        }
-    }
-
-    // Domains to test
-    const char* names[] = {
-        "*.foo.*.bar.example.org",
-        "foo.*.bar.example.org",
-        "*.bar.example.org",
-        "bar.example.org",
-        NULL
-    };
-
-    {
-        SCOPED_TRACE("Asking directly for A on parent nodes");
-
-        for (const char** name = names; *name != NULL; ++ name) {
-            SCOPED_TRACE(string("Node ") + *name);
-            findTest(Name(*name), RRType::A(), ZoneFinder::NXRRSET);
-        }
-    }
-
-    {
-        SCOPED_TRACE("Asking for ANY on parent nodes");
-
-        for (const char** name = names; *name != NULL; ++ name) {
-            SCOPED_TRACE(string("Node ") + *name);
-
-            findAllTest(Name(*name), ZoneFinder::NXRRSET,
-                        vector<ConstRRsetPtr>());
-        }
-    }
-}
-
-// We run this part twice from the below test, in two slightly different
-// situations
-void
-InMemoryZoneFinderTest::doCancelWildcardCheck(
-    ZoneFinder::FindResultFlags expected_flags,
-    ZoneFinder::FindOptions find_options)
-{
-    // These should be canceled
-    {
-        SCOPED_TRACE("Canceled under foo.wild.example.org");
-
-        // For an NSEC-signed zone with DNSSEC requested, the covering NSEC
-        // should be returned.  The expected NSEC is actually just the only
-        // NSEC in the test data, but in this context it doesn't matter;
-        // it's sufficient just to check any NSEC is returned (or not).
-        ConstRRsetPtr expected_nsec; // by default it's NULL
-        if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0 &&
-            (find_options & ZoneFinder::FIND_DNSSEC)) {
-            expected_nsec = rr_nsec_;
-        }
-
-        findTest(Name("aaa.foo.wild.example.org"), RRType::A(),
-                 ZoneFinder::NXDOMAIN, true, expected_nsec, expected_flags,
-                 NULL, find_options);
-        findTest(Name("zzz.foo.wild.example.org"), RRType::A(),
-                 ZoneFinder::NXDOMAIN, true, expected_nsec, expected_flags,
-                 NULL, find_options);
-    }
-
-    // This is existing, non-wildcard domain, shouldn't wildcard at all
-    {
-        SCOPED_TRACE("Existing domain under foo.wild.example.org");
-        findTest(Name("bar.foo.wild.example.org"), RRType::A(),
-                 ZoneFinder::SUCCESS, true, rr_not_wild_);
-    }
-
-    // These should be caught by the wildcard
-    {
-        SCOPED_TRACE("Neighbor wildcards to foo.wild.example.org");
-
-        const char* names[] = {
-            "aaa.bbb.wild.example.org",
-            "aaa.zzz.wild.example.org",
-            "zzz.wild.example.org",
-            NULL
-        };
-
-        for (const char** name = names; *name != NULL; ++ name) {
-            SCOPED_TRACE(string("Node ") + *name);
-
-            findTest(Name(*name), RRType::A(), ZoneFinder::SUCCESS, false,
-                     rr_wild_,
-                     ZoneFinder::RESULT_WILDCARD | expected_flags, NULL,
-                     ZoneFinder::FIND_DEFAULT, true);
-        }
-    }
-
-    // This shouldn't be wildcarded, it's an existing domain
-    {
-        SCOPED_TRACE("The foo.wild.example.org itself");
-        findTest(Name("foo.wild.example.org"), RRType::A(),
-                 ZoneFinder::NXRRSET, true, ConstRRsetPtr(), expected_flags);
-    }
-}
-
-/*
- * This tests that if there's a name between the wildcard domain and the
- * searched one, it will not trigger wildcard, for example, if we have
- * *.wild.example.org and bar.foo.wild.example.org, then we know
- * foo.wild.example.org exists and is not wildcard. Therefore, search for
- * aaa.foo.wild.example.org should return NXDOMAIN.
- *
- * Tests few cases "around" the canceled wildcard match, to see something that
- * shouldn't be canceled isn't.
- */
-TEST_F(InMemoryZoneFinderTest, cancelWildcard) {
-    addZoneData(rr_wild_);
-    addZoneData(rr_not_wild_);
-
-    {
-        SCOPED_TRACE("Runnig with single entry under foo.wild.example.org");
-        doCancelWildcardCheck();
-    }
-
-    // Try putting another one under foo.wild....
-    // The result should be the same but it will be done in another way in the
-    // code, because the foo.wild.example.org will exist in the tree.
-    addZoneData(rr_not_wild_another_);
-    {
-        SCOPED_TRACE("Runnig with two entries under foo.wild.example.org");
-        doCancelWildcardCheck();
-    }
-}
-
-// Same tests as cancelWildcard for NSEC3-signed zone
-TEST_F(InMemoryZoneFinderTest, cancelWildcardNSEC3) {
-    addZoneData(rr_wild_);
-    addZoneData(rr_not_wild_);
-    addZoneData(rr_nsec3_);
-
-    {
-        SCOPED_TRACE("Runnig with single entry under foo.wild.example.org");
-        doCancelWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
-    }
-    addZoneData(rr_not_wild_another_);
-    {
-        SCOPED_TRACE("Runnig with two entries under foo.wild.example.org");
-        doCancelWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
-    }
-}
-
-// Same tests as cancelWildcard for NSEC-signed zone.  Check both cases with
-// or without FIND_DNSSEC option.  NSEC should be returned only when the option
-// is given.
-TEST_F(InMemoryZoneFinderTest, cancelWildcardNSEC) {
-    addZoneData(rr_wild_);
-    addZoneData(rr_not_wild_);
-    addZoneData(rr_nsec_);
-
-    {
-        SCOPED_TRACE("Runnig with single entry under foo.wild.example.org");
-        doCancelWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED,
-                              ZoneFinder::FIND_DNSSEC);
-        doCancelWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED);
-    }
-    addZoneData(rr_not_wild_another_);
-    {
-        SCOPED_TRACE("Runnig with two entries under foo.wild.example.org");
-        doCancelWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED,
-                              ZoneFinder::FIND_DNSSEC);
-        doCancelWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED);
-    }
-}
-
-
-// DISABLED: nsec3 will be re-added in #2118
-TEST_F(InMemoryZoneFinderTest, DISABLED_findNSEC3) {
-    // Set up the faked hash calculator.
-    setNSEC3HashCreator(&nsec3_hash_creator_);
-
-    // Add a few NSEC3 records:
-    // apex (example.org.): hash=0P..
-    // ns1.example.org:     hash=2T..
-    // w.example.org:       hash=01..
-    // zzz.example.org:     hash=R5..
-    const string apex_nsec3_text = string(apex_hash) + ".example.org." +
-        string(nsec3_common);
-    addZoneData(textToRRset(apex_nsec3_text));
-    const string ns1_nsec3_text = string(ns1_hash) + ".example.org." +
-        string(nsec3_common);
-    addZoneData(textToRRset(ns1_nsec3_text));
-    const string w_nsec3_text = string(w_hash) + ".example.org." +
-        string(nsec3_common);
-    addZoneData(textToRRset(w_nsec3_text));
-    const string zzz_nsec3_text = string(zzz_hash) + ".example.org." +
-        string(nsec3_common);
-    addZoneData(textToRRset(zzz_nsec3_text));
-
-    performNSEC3Test(zone_finder_);
-}
-
-// DISABLED: NSEC3 will be re-added in #2218
-TEST_F(InMemoryZoneFinderTest, DISABLED_findNSEC3ForBadZone) {
-    // Set up the faked hash calculator.
-    setNSEC3HashCreator(&nsec3_hash_creator_);
-
-    // If the zone has nothing about NSEC3 (neither NSEC3 or NSEC3PARAM),
-    // findNSEC3() should be rejected.
-    EXPECT_THROW(zone_finder_.findNSEC3(Name("www.example.org"), true),
-                 DataSourceError);
-
-    // Only having NSEC3PARAM isn't enough
-    addZoneData(textToRRset("example.org. 300 IN NSEC3PARAM "
-                            "1 0 12 aabbccdd"));
-    EXPECT_THROW(zone_finder_.findNSEC3(Name("www.example.org"), true),
-                 DataSourceError);
-
-    // Unless NSEC3 for apex is added the result in the recursive mode
-    // is guaranteed.
-    const string ns1_nsec3_text = string(ns1_hash) + ".example.org." +
-        string(nsec3_common);
-    addZoneData(textToRRset(ns1_nsec3_text));
-    EXPECT_THROW(zone_finder_.findNSEC3(Name("www.example.org"), true),
-                 DataSourceError);
-}
-
-}
diff --git a/src/lib/datasrc/memory/tests/zone_table_unittest.cc b/src/lib/datasrc/memory/tests/zone_table_unittest.cc
deleted file mode 100644
index 359df49..0000000
--- a/src/lib/datasrc/memory/tests/zone_table_unittest.cc
+++ /dev/null
@@ -1,150 +0,0 @@
-// 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 <exceptions/exceptions.h>
-
-#include <util/memory_segment_local.h>
-
-#include <dns/name.h>
-#include <dns/rrclass.h>
-
-#include <datasrc/result.h>
-#include <datasrc/memory/zone_data.h>
-#include <datasrc/memory/zone_table.h>
-
-#include <gtest/gtest.h>
-
-#include <new>                  // for bad_alloc
-
-using namespace isc::dns;
-using namespace isc::datasrc;
-using namespace isc::datasrc::memory;
-
-namespace {
-// Memory segment specified for tests.  It normally behaves like a "local"
-// memory segment.  If "throw count" is set to non 0 via setThrowCount(),
-// it continues the normal behavior up to the specified number of calls to
-// allocate(), and throws an exception at the next call.
-class TestMemorySegment : public isc::util::MemorySegmentLocal {
-public:
-    TestMemorySegment() : throw_count_(0) {}
-    virtual void* allocate(size_t size) {
-        if (throw_count_ > 0) {
-            if (--throw_count_ == 0) {
-                throw std::bad_alloc();
-            }
-        }
-        return (isc::util::MemorySegmentLocal::allocate(size));
-    }
-    void setThrowCount(size_t count) { throw_count_ = count; }
-
-private:
-    size_t throw_count_;
-};
-
-class ZoneTableTest : public ::testing::Test {
-protected:
-    ZoneTableTest() : zclass_(RRClass::IN()),
-                      zname1(Name("example.com")),
-                      zname2(Name("example.net")),
-                      zname3(Name("example")),
-                      zone_table(ZoneTable::create(mem_sgmt_, zclass_))
-    {}
-    ~ZoneTableTest() {
-        if (zone_table != NULL) {
-            ZoneTable::destroy(mem_sgmt_, zone_table, zclass_);
-        }
-    }
-    void TearDown() {
-        ZoneTable::destroy(mem_sgmt_, zone_table, zclass_);
-        zone_table = NULL;
-        EXPECT_TRUE(mem_sgmt_.allMemoryDeallocated()); // catch any leak here.
-    }
-    const RRClass zclass_;
-    const Name zname1, zname2, zname3;
-    TestMemorySegment mem_sgmt_;
-    ZoneTable* zone_table;
-};
-
-TEST_F(ZoneTableTest, create) {
-    // Test about creating a zone table.  Normal case covers through other
-    // tests.  We only check exception safety by letting the test memory
-    // segment throw.
-    mem_sgmt_.setThrowCount(2);
-    EXPECT_THROW(ZoneTable::create(mem_sgmt_, zclass_), std::bad_alloc);
-    // This shouldn't cause memory leak (that would be caught in TearDown()).
-}
-
-TEST_F(ZoneTableTest, addZone) {
-    // Normal successful case.
-    const ZoneTable::AddResult result1 =
-        zone_table->addZone(mem_sgmt_, zclass_, zname1);
-    EXPECT_EQ(result::SUCCESS, result1.code);
-
-    // Duplicate add doesn't replace the existing data.
-    EXPECT_EQ(result::EXIST, zone_table->addZone(mem_sgmt_, zclass_,
-                                                 zname1).code);
-    EXPECT_EQ(result1.zone_data,
-              zone_table->addZone(mem_sgmt_, zclass_, zname1).zone_data);
-    // names are compared in a case insensitive manner.
-    EXPECT_EQ(result::EXIST, zone_table->addZone(mem_sgmt_, zclass_,
-                                                 Name("EXAMPLE.COM")).code);
-    // Add some more different ones.  Should just succeed.
-    EXPECT_EQ(result::SUCCESS,
-              zone_table->addZone(mem_sgmt_, zclass_, zname2).code);
-    EXPECT_EQ(result::SUCCESS,
-              zone_table->addZone(mem_sgmt_, zclass_, zname3).code);
-
-    // Have the memory segment throw an exception in extending the internal
-    // tree.  It still shouldn't cause memory leak (which would be detected
-    // in TearDown()).
-    mem_sgmt_.setThrowCount(2);
-    EXPECT_THROW(zone_table->addZone(mem_sgmt_, zclass_, Name("example.org")),
-                 std::bad_alloc);
-}
-
-TEST_F(ZoneTableTest, findZone) {
-    const ZoneTable::AddResult add_result1 =
-        zone_table->addZone(mem_sgmt_, zclass_, zname1);
-    EXPECT_EQ(result::SUCCESS, add_result1.code);
-    EXPECT_EQ(result::SUCCESS,
-              zone_table->addZone(mem_sgmt_, zclass_, zname2).code);
-    EXPECT_EQ(result::SUCCESS,
-              zone_table->addZone(mem_sgmt_, zclass_, zname3).code);
-
-    const ZoneTable::FindResult find_result1 =
-        zone_table->findZone(Name("example.com"));
-    EXPECT_EQ(result::SUCCESS, find_result1.code);
-    EXPECT_EQ(add_result1.zone_data, find_result1.zone_data);
-
-    EXPECT_EQ(result::NOTFOUND,
-              zone_table->findZone(Name("example.org")).code);
-    EXPECT_EQ(static_cast<ZoneData*>(NULL),
-              zone_table->findZone(Name("example.org")).zone_data);
-
-    // there's no exact match.  the result should be the longest match,
-    // and the code should be PARTIALMATCH.
-    EXPECT_EQ(result::PARTIALMATCH,
-              zone_table->findZone(Name("www.example.com")).code);
-    EXPECT_EQ(add_result1.zone_data,
-              zone_table->findZone(Name("www.example.com")).zone_data);
-
-    // make sure the partial match is indeed the longest match by adding
-    // a zone with a shorter origin and query again.
-    EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zclass_,
-                                                   Name("com")).code);
-    EXPECT_EQ(add_result1.zone_data,
-              zone_table->findZone(Name("www.example.com")).zone_data);
-}
-}
diff --git a/src/lib/datasrc/memory/treenode_rrset.cc b/src/lib/datasrc/memory/treenode_rrset.cc
index fb7cafc..f51b2f9 100644
--- a/src/lib/datasrc/memory/treenode_rrset.cc
+++ b/src/lib/datasrc/memory/treenode_rrset.cc
@@ -79,10 +79,6 @@ TreeNodeRRset::setTTL(const RRTTL&) {
 
 std::string
 TreeNodeRRset::toText() const {
-    // Create TTL from internal data
-    util::InputBuffer ttl_buffer(rdataset_->getTTLData(), sizeof(uint32_t));
-    const RRTTL ttl(ttl_buffer);
-
     // Dump the main RRset, if not empty
     std::string ret;
     RRsetPtr tmp_rrset;
@@ -92,7 +88,7 @@ TreeNodeRRset::toText() const {
     {
         if (!tmp_rrset) {
             tmp_rrset = RRsetPtr(new RRset(getName(), rrclass_, getType(),
-                                           ttl));
+                                           getTTL()));
         }
         tmp_rrset->addRdata(rit->getCurrent());
     }
@@ -101,17 +97,7 @@ TreeNodeRRset::toText() const {
     }
 
     // Dump any RRSIGs
-    tmp_rrset.reset();
-    for (RdataIteratorPtr rit = getSigRdataIterator();
-         !rit->isLast();
-         rit->next())
-    {
-        if (!tmp_rrset) {
-            tmp_rrset = RRsetPtr(new RRset(getName(), rrclass_,
-                                           RRType::RRSIG(), ttl));
-        }
-        tmp_rrset->addRdata(rit->getCurrent());
-    }
+    tmp_rrset = getRRsig();
     if (tmp_rrset) {
         ret += tmp_rrset->toText();
     }
@@ -292,7 +278,26 @@ TreeNodeRRset::getSigRdataIterator() const {
 
 RRsetPtr
 TreeNodeRRset::getRRsig() const {
-    isc_throw(Unexpected, "unexpected method called on TreeNodeRRset");
+    // Shortcut: if DNSSEC is disabled for the RRset, simply return NULL.
+    // The generic code below provides the same behavior, but with much more
+    // overhead.
+    if (!dnssec_ok_) {
+        return (RRsetPtr());
+    }
+
+    RRsetPtr tmp_rrset;
+    for (RdataIteratorPtr rit = getSigRdataIterator();
+         !rit->isLast();
+         rit->next())
+    {
+        if (!tmp_rrset) {
+            tmp_rrset = RRsetPtr(new RRset(getName(), rrclass_,
+                                           RRType::RRSIG(), getTTL()));
+        }
+        tmp_rrset->addRdata(rit->getCurrent());
+    }
+
+    return (tmp_rrset);
 }
 
 void
diff --git a/src/lib/datasrc/memory/treenode_rrset.h b/src/lib/datasrc/memory/treenode_rrset.h
index a5f48bf..460a704 100644
--- a/src/lib/datasrc/memory/treenode_rrset.h
+++ b/src/lib/datasrc/memory/treenode_rrset.h
@@ -190,8 +190,6 @@ public:
     virtual dns::RdataIteratorPtr getRdataIterator() const;
 
     /// \brief Specialized version of \c getRRsig() for \c TreeNodeRRset.
-    ///
-    /// It throws \c isc::Unexpected unconditionally.
     virtual dns::RRsetPtr getRRsig() const;
 
     virtual unsigned int getRRsigDataCount() const {
diff --git a/src/lib/datasrc/memory/zone_finder.cc b/src/lib/datasrc/memory/zone_finder.cc
index cb56b8f..00c6cd6 100644
--- a/src/lib/datasrc/memory/zone_finder.cc
+++ b/src/lib/datasrc/memory/zone_finder.cc
@@ -15,6 +15,7 @@
 #include <datasrc/memory/zone_finder.h>
 #include <datasrc/memory/domaintree.h>
 #include <datasrc/memory/treenode_rrset.h>
+#include <datasrc/memory/rdata_serialization.h>
 
 #include <datasrc/zone.h>
 #include <datasrc/data_source.h>
@@ -22,9 +23,16 @@
 #include <dns/name.h>
 #include <dns/rrset.h>
 #include <dns/rrtype.h>
+#include <dns/nsec3hash.h>
 
 #include <datasrc/logger.h>
 
+#include <boost/scoped_ptr.hpp>
+#include <boost/bind.hpp>
+
+#include <algorithm>
+#include <vector>
+
 using namespace isc::dns;
 using namespace isc::datasrc::memory;
 using namespace isc::datasrc;
@@ -33,6 +41,37 @@ namespace isc {
 namespace datasrc {
 namespace memory {
 
+namespace internal {
+
+// Specialized version of ZoneFinder::ResultContext, which  holds objects
+// related to find() results using internal representations of the in-memory
+// data source implementation.
+class ZoneFinderResultContext {
+public:
+    /// \brief Constructor
+    ///
+    /// The first three parameters correspond to those of
+    /// ZoneFinder::ResultContext.  If node is non NULL, it specifies the
+    /// found ZoneNode in the search.
+    ZoneFinderResultContext(ZoneFinder::Result code_param,
+                            TreeNodeRRsetPtr rrset_param,
+                            ZoneFinder::FindResultFlags flags_param,
+                            const ZoneData& zone_data_param,
+                            const ZoneNode* node, const RdataSet* rdset) :
+        code(code_param), rrset(rrset_param), flags(flags_param),
+        zone_data(&zone_data_param), found_node(node), found_rdset(rdset)
+    {}
+
+    const ZoneFinder::Result code;
+    const TreeNodeRRsetPtr rrset;
+    const ZoneFinder::FindResultFlags flags;
+    const ZoneData* const zone_data;
+    const ZoneNode* const found_node;
+    const RdataSet* const found_rdset;
+};
+}
+using internal::ZoneFinderResultContext;
+
 namespace {
 /// Creates a TreeNodeRRsetPtr for the given RdataSet at the given Node, for
 /// the given RRClass
@@ -51,18 +90,21 @@ TreeNodeRRsetPtr
 createTreeNodeRRset(const ZoneNode* node,
                     const RdataSet* rdataset,
                     const RRClass& rrclass,
+                    ZoneFinder::FindOptions options,
                     const Name* realname = NULL)
 {
+    const bool dnssec = ((options & ZoneFinder::FIND_DNSSEC) != 0);
     if (node != NULL && rdataset != NULL) {
         if (realname != NULL) {
-            return TreeNodeRRsetPtr(new TreeNodeRRset(*realname, rrclass, node,
-                                                      rdataset, true));
+            return (TreeNodeRRsetPtr(new TreeNodeRRset(*realname, rrclass,
+                                                       node, rdataset,
+                                                       dnssec)));
         } else {
-            return TreeNodeRRsetPtr(new TreeNodeRRset(rrclass, node,
-                                                      rdataset, true));
+            return (TreeNodeRRsetPtr(new TreeNodeRRset(rrclass, node, rdataset,
+                                                       dnssec)));
         }
     } else {
-        return TreeNodeRRsetPtr();
+        return (TreeNodeRRsetPtr());
     }
 }
 
@@ -145,6 +187,27 @@ bool cutCallback(const ZoneNode& node, FindState* state) {
     return (false);
 }
 
+/// Creates a NSEC3 ConstRRsetPtr for the given ZoneNode inside the
+/// NSEC3 tree, for the given RRClass.
+///
+/// It asserts that the node contains data (RdataSet) and is of type
+/// NSEC3.
+///
+/// \param node The ZoneNode inside the NSEC3 tree
+/// \param rrclass The RRClass as passed by the client
+ConstRRsetPtr
+createNSEC3RRset(const ZoneNode* node, const RRClass& rrclass) {
+     const RdataSet* rdataset = node->getData();
+     // Only NSEC3 ZoneNodes are allowed to be passed to this method. We
+     // assert that these have data, and also are of type NSEC3.
+     assert(rdataset != NULL);
+     assert(rdataset->type == RRType::NSEC3());
+
+    // Create the RRset.  Note the DNSSEC flag: NSEC3 implies DNSSEC.
+    return (createTreeNodeRRset(node, rdataset, rrclass,
+                                ZoneFinder::FIND_DNSSEC));
+}
+
 // convenience function to fill in the final details
 //
 // Set up ZoneFinderResultContext object as a return value of find(),
@@ -158,14 +221,16 @@ bool cutCallback(const ZoneNode& node, FindState* state) {
 // if wild is true, the RESULT_WILDCARD flag will be set.
 // If qname is not NULL, this is the query name, to be used in wildcard
 // substitution instead of the Node's name).
-isc::datasrc::memory::ZoneFinderResultContext
+ZoneFinderResultContext
 createFindResult(const RRClass& rrclass,
                  const ZoneData& zone_data,
                  ZoneFinder::Result code,
-                 const RdataSet* rrset,
+                 const RdataSet* rdset,
                  const ZoneNode* node,
+                 ZoneFinder::FindOptions options,
                  bool wild = false,
-                 const Name* qname = NULL) {
+                 const Name* qname = NULL)
+{
     ZoneFinder::FindResultFlags flags = ZoneFinder::RESULT_DEFAULT;
     const Name* rename = NULL;
 
@@ -182,9 +247,10 @@ createFindResult(const RRClass& rrclass,
         }
     }
 
-    return (ZoneFinderResultContext(code, createTreeNodeRRset(node, rrset,
-                                                              rrclass, rename),
-                                    flags, node));
+    return (ZoneFinderResultContext(code, createTreeNodeRRset(node, rdset,
+                                                              rrclass, options,
+                                                              rename),
+                                    flags, zone_data, node, rdset));
 }
 
 // A helper function for NSEC-signed zones.  It searches the zone for
@@ -341,19 +407,22 @@ public:
 // caught above.
 //
 // If none of the above succeeds, we conclude the name doesn't exist in
-// the zone, and throw an OutOfZone exception.
+// the zone, and throw an OutOfZone exception by default.  If the optional
+// out_of_zone_ok is true, it returns an NXDOMAIN result with NULL data so
+// the caller can take an action to it (technically it's not "NXDOMAIN",
+// but the caller is assumed not to rely on the difference.)
 FindNodeResult findNode(const ZoneData& zone_data,
-                        const Name& name,
+                        const LabelSequence& name_labels,
                         ZoneChain& node_path,
-                        ZoneFinder::FindOptions options)
+                        ZoneFinder::FindOptions options,
+                        bool out_of_zone_ok = false)
 {
     ZoneNode* node = NULL;
     FindState state((options & ZoneFinder::FIND_GLUE_OK) != 0);
 
     const ZoneTree& tree(zone_data.getZoneTree());
-    ZoneTree::Result result = tree.find(isc::dns::LabelSequence(name),
-                                        &node, node_path, cutCallback,
-                                        &state);
+    const ZoneTree::Result result = tree.find(name_labels, &node, node_path,
+                                              cutCallback, &state);
     const unsigned int zonecut_flag =
         (state.zonecut_node_ != NULL) ? FindNodeResult::FIND_ZONECUT : 0;
     if (result == ZoneTree::EXACTMATCH) {
@@ -377,7 +446,7 @@ FindNodeResult findNode(const ZoneData& zone_data,
         if (node_path.getLastComparisonResult().getRelation() ==
             NameComparisonResult::SUPERDOMAIN) { // empty node, so NXRRSET
             LOG_DEBUG(logger, DBG_TRACE_DATA,
-                      DATASRC_MEM_SUPER_STOP).arg(name);
+                      DATASRC_MEM_SUPER_STOP).arg(name_labels);
             const ZoneNode* nsec_node;
             const RdataSet* nsec_rds = getClosestNSEC(zone_data,
                                                       node_path,
@@ -398,7 +467,7 @@ FindNodeResult findNode(const ZoneData& zone_data,
                 // baz.foo.wild.example. The common ancestor, foo.wild.example,
                 // should cancel wildcard.  Treat it as NXDOMAIN.
                 LOG_DEBUG(logger, DBG_TRACE_DATA,
-                          DATASRC_MEM_WILDCARD_CANCEL).arg(name);
+                          DATASRC_MEM_WILDCARD_CANCEL).arg(name_labels);
                     const ZoneNode* nsec_node;
                     const RdataSet* nsec_rds = getClosestNSEC(zone_data,
                                                               node_path,
@@ -431,53 +500,198 @@ FindNodeResult findNode(const ZoneData& zone_data,
                         FindNodeResult::FIND_WILDCARD | zonecut_flag));
         }
 
-        LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_NOT_FOUND).arg(name);
+        LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_NOT_FOUND).
+            arg(name_labels);
         const ZoneNode* nsec_node;
         const RdataSet* nsec_rds = getClosestNSEC(zone_data, node_path,
                                                   &nsec_node, options);
         return (FindNodeResult(ZoneFinder::NXDOMAIN, nsec_node, nsec_rds));
     } else {
         // If the name is neither an exact or partial match, it is
-        // out of bailiwick, which is considered an error.
-        isc_throw(OutOfZone, name.toText() << " not in " <<
+        // out of bailiwick, which is considered an error, unless the caller
+        // is willing to accept it.
+        if (out_of_zone_ok) {
+            return (FindNodeResult(ZoneFinder::NXDOMAIN, NULL, NULL));
+        }
+        isc_throw(OutOfZone, name_labels << " not in " <<
                              zone_data.getOriginNode()->getName());
     }
 }
 
 } // end anonymous namespace
 
-// Specialization of the ZoneFinder::Context for the in-memory finder.
+
+/// \brief Specialization of the ZoneFinder::Context for the in-memory finder.
+///
+/// Note that we don't have a specific constructor for the findAll() case.
+/// For (successful) type ANY query, found_node points to the
+/// corresponding zone node, which is recorded within this specialized
+/// context.
 class InMemoryZoneFinder::Context : public ZoneFinder::Context {
 public:
-    /// \brief Constructor.
-    ///
-    /// Note that we don't have a specific constructor for the findAll() case.
-    /// For (successful) type ANY query, found_node points to the
-    /// corresponding RB node, which is recorded within this specialized
-    /// context.
     Context(ZoneFinder& finder, ZoneFinder::FindOptions options,
-            ZoneFinderResultContext result) :
+            const RRClass& rrclass, const ZoneFinderResultContext& result) :
         ZoneFinder::Context(finder, options,
                             ResultContext(result.code, result.rrset,
                                           result.flags)),
-        rrset_(result.rrset), found_node_(result.found_node)
+        rrclass_(rrclass), zone_data_(result.zone_data),
+        found_node_(result.found_node),
+        found_rdset_(result.found_rdset)
     {}
 
+protected:
+    virtual void getAdditionalImpl(const std::vector<RRType>& requested_types,
+                                   std::vector<ConstRRsetPtr>& result)
+    {
+        if (found_rdset_ != NULL) {
+            // Normal query with successful result.
+            getAdditionalForRdataset(found_rdset_, requested_types, result,
+                                     options_);
+        } else if (found_node_ != NULL) {
+            // Successful type ANY query result.  Call
+            // getAdditionalForRdataset for each RdataSet of the node.
+            for (const RdataSet* rdset = found_node_->getData();
+                 rdset != NULL;
+                 rdset = rdset->getNext())
+            {
+                getAdditionalForRdataset(rdset, requested_types, result,
+                                         options_);
+            }
+        }
+    }
+
 private:
-    const TreeNodeRRsetPtr rrset_;
+    // Main subroutine of getAdditionalImpl, iterate over Rdata fields
+    // find, create, and insert necessary additional RRsets.
+    void
+    getAdditionalForRdataset(const RdataSet* rdset,
+                             const std::vector<RRType>& requested_types,
+                             std::vector<ConstRRsetPtr>& result,
+                             ZoneFinder::FindOptions orig_options) const
+    {
+        ZoneFinder::FindOptions options = ZoneFinder::FIND_DEFAULT;
+        if ((orig_options & ZoneFinder::FIND_DNSSEC) != 0) {
+            options = options | ZoneFinder::FIND_DNSSEC;
+        }
+        if (rdset->type == RRType::NS()) {
+            options = options | ZoneFinder::FIND_GLUE_OK;
+        }
+
+        RdataReader(rrclass_, rdset->type, rdset->getDataBuf(),
+                    rdset->getRdataCount(), rdset->getSigRdataCount(),
+                    boost::bind(&Context::findAdditional, this,
+                                &requested_types, &result, options, _1, _2),
+                    &RdataReader::emptyDataAction).iterate();
+    }
+
+    // RdataReader callback for additional section processing.
+    void
+    findAdditional(const std::vector<RRType>* requested_types,
+                   std::vector<ConstRRsetPtr>* result,
+                   ZoneFinder::FindOptions options,
+                   const LabelSequence& name_labels,
+                   RdataNameAttributes attr) const;
+
+    // Subroutine for findAdditional() to unify the normal and wildcard match
+    // cases.
+    void
+    findAdditionalHelper(const std::vector<RRType>* requested_types,
+                         std::vector<ConstRRsetPtr>* result,
+                         const ZoneNode* node,
+                         ZoneFinder::FindOptions options,
+                         const Name* real_name) const
+    {
+        const std::vector<RRType>::const_iterator type_beg =
+            requested_types->begin();
+        const std::vector<RRType>::const_iterator type_end =
+            requested_types->end();
+        for (const RdataSet* rdset = node->getData();
+             rdset != NULL;
+             rdset = rdset->getNext())
+        {
+            // Checking all types for all RdataSets could be suboptimal.
+            // This can be a bit more optimized, but unless we have many
+            // requested types the effect is probably marginal.  For now we
+            // keep it simple.
+            if (std::find(type_beg, type_end, rdset->type) != type_end) {
+                result->push_back(createTreeNodeRRset(node, rdset, rrclass_,
+                                                      options, real_name));
+            }
+        }
+    }
+
+private:
+    const RRClass rrclass_;
+    const ZoneData* const zone_data_;
     const ZoneNode* const found_node_;
+    const RdataSet* const found_rdset_;
 };
 
+void
+InMemoryZoneFinder::Context::findAdditional(
+    const std::vector<RRType>* requested_types,
+    std::vector<ConstRRsetPtr>* result,
+    ZoneFinder::FindOptions options,
+    const LabelSequence& name_labels,
+    RdataNameAttributes attr) const
+{
+    // Ignore name data that don't need additional processing.
+    if ((attr & NAMEATTR_ADDITIONAL) == 0) {
+        return;
+    }
+
+    // Find the zone node for the additional name.  By passing true as the
+    // last parameter of findNode() we ignore out-of-zone names.
+    ZoneChain node_path;
+    const FindNodeResult node_result =
+        findNode(*zone_data_, name_labels, node_path, options, true);
+    // we only need non-empty exact match
+    if (node_result.code != SUCCESS) {
+        return;
+    }
+
+    // Ignore data at a zone cut (due to subdomain delegation) unless glue is
+    // allowed.  Checking the node callback flag is a cheap way to detect
+    // zone cuts, but it includes DNAME delegation, in which case we should
+    // keep finding the additional records regardless of the 'GLUE_OK' flag.
+    // The last two conditions limit the case to delegation NS, i.e, the node
+    // has an NS and it's not the zone origin.
+    const ZoneNode* node = node_result.node;
+    if ((options & ZoneFinder::FIND_GLUE_OK) == 0 &&
+        node->getFlag(ZoneNode::FLAG_CALLBACK) &&
+        node != zone_data_->getOriginNode() &&
+        RdataSet::find(node->getData(), RRType::NS()) != NULL) {
+        return;
+    }
+
+    // Examine RdataSets of the node, and create and insert requested types
+    // of RRsets as we find them.
+    if ((node_result.flags & FindNodeResult::FIND_WILDCARD) == 0) {
+        // normal case
+        findAdditionalHelper(requested_types, result, node, options, NULL);
+    } else {
+        // if the additional name is subject to wildcard substitution, we need
+        // to create a name object for the "real" (after substitution) name.
+        // This is expensive, but in the additional processing this should be
+        // very rare cases and acceptable.
+        size_t data_len;
+        const uint8_t* data;
+        data = name_labels.getData(&data_len);
+        util::InputBuffer buffer(data, data_len);
+        const Name real_name(buffer);
+        findAdditionalHelper(requested_types, result, node, options,
+                             &real_name);
+    }
+}
+
 boost::shared_ptr<ZoneFinder::Context>
 InMemoryZoneFinder::find(const isc::dns::Name& name,
                 const isc::dns::RRType& type,
                 const FindOptions options)
 {
-    return ZoneFinderContextPtr(new Context(*this, options,
-                                            find_internal(name,
-                                                          type,
-                                                          NULL,
-                                                          options)));
+    return (ZoneFinderContextPtr(new Context(*this, options, rrclass_,
+                                             find_internal(name, type,
+                                                           NULL, options))));
 }
 
 boost::shared_ptr<ZoneFinder::Context>
@@ -485,11 +699,11 @@ InMemoryZoneFinder::findAll(const isc::dns::Name& name,
         std::vector<isc::dns::ConstRRsetPtr>& target,
         const FindOptions options)
 {
-    return ZoneFinderContextPtr(new Context(*this, options,
-                                            find_internal(name,
-                                                          RRType::ANY(),
-                                                          &target,
-                                                          options)));
+    return (ZoneFinderContextPtr(new Context(*this, options, rrclass_,
+                                             find_internal(name,
+                                                           RRType::ANY(),
+                                                           &target,
+                                                           options))));
 }
 
 ZoneFinderResultContext
@@ -502,10 +716,11 @@ InMemoryZoneFinder::find_internal(const isc::dns::Name& name,
     // in findNode().  We simply construct a result structure and return.
     ZoneChain node_path;
     const FindNodeResult node_result =
-        findNode(zone_data_, name, node_path, options);
+        findNode(zone_data_, LabelSequence(name), node_path, options);
     if (node_result.code != SUCCESS) {
         return (createFindResult(rrclass_, zone_data_, node_result.code,
-                                 node_result.rrset, node_result.node));
+                                 node_result.rrset, node_result.node,
+                                 options));
     }
 
     const ZoneNode* node = node_result.node;
@@ -524,25 +739,26 @@ InMemoryZoneFinder::find_internal(const isc::dns::Name& name,
         const RdataSet* nsec_rds = getClosestNSEC(zone_data_, node_path,
                                                   &nsec_node, options);
         return (createFindResult(rrclass_, zone_data_, NXRRSET,
-                                 nsec_rds,
-                                 nsec_node,
-                                 wild));
+                                 nsec_rds, nsec_node, options, wild));
     }
 
     const RdataSet* found;
 
     // If the node callback is enabled, this may be a zone cut.  If it
     // has a NS RR, we should return a delegation, but not in the apex.
-    // There is one exception: the case for DS query, which should always
-    // be considered in-zone lookup.
+    // There are two exceptions:
+    // - the case for DS query, which should always be considered in-zone
+    //   lookup.
+    // - when we are looking for glue records (FIND_GLUE_OK)
     if (node->getFlag(ZoneNode::FLAG_CALLBACK) &&
-            node != zone_data_.getOriginNode() && type != RRType::DS()) {
+        (options & FIND_GLUE_OK) == 0 &&
+        node != zone_data_.getOriginNode() && type != RRType::DS()) {
         found = RdataSet::find(node->getData(), RRType::NS());
         if (found != NULL) {
             LOG_DEBUG(logger, DBG_TRACE_DATA,
                       DATASRC_MEM_EXACT_DELEGATION).arg(name);
             return (createFindResult(rrclass_, zone_data_, DELEGATION,
-                                     found, node, wild, &name));
+                                     found, node, options, wild, &name));
         }
     }
 
@@ -552,13 +768,13 @@ InMemoryZoneFinder::find_internal(const isc::dns::Name& name,
         const RdataSet* cur_rds = node->getData();
         while (cur_rds != NULL) {
             target->push_back(createTreeNodeRRset(node, cur_rds, rrclass_,
-                                                  &name));
+                                                  options, &name));
             cur_rds = cur_rds->getNext();
         }
         LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_ANY_SUCCESS).
             arg(name);
         return (createFindResult(rrclass_, zone_data_, SUCCESS, NULL, node,
-                                 wild, &name));
+                                 options, wild, &name));
     }
 
     found = RdataSet::find(node->getData(), type);
@@ -567,7 +783,7 @@ InMemoryZoneFinder::find_internal(const isc::dns::Name& name,
         LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_SUCCESS).arg(name).
             arg(type);
         return (createFindResult(rrclass_, zone_data_, SUCCESS, found, node,
-                                 wild, &name));
+                                 options, wild, &name));
     } else {
         // Next, try CNAME.
         found = RdataSet::find(node->getData(), RRType::CNAME());
@@ -575,20 +791,166 @@ InMemoryZoneFinder::find_internal(const isc::dns::Name& name,
 
             LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_CNAME).arg(name);
             return (createFindResult(rrclass_, zone_data_, CNAME, found, node,
-                                     wild, &name));
+                                     options, wild, &name));
         }
     }
     // No exact match or CNAME.  Get NSEC if necessary and return NXRRSET.
     return (createFindResult(rrclass_, zone_data_, NXRRSET,
                              getNSECForNXRRSET(zone_data_, options, node),
-                             node, wild, &name));
+                             node, options, wild, &name));
 }
 
 isc::datasrc::ZoneFinder::FindNSEC3Result
 InMemoryZoneFinder::findNSEC3(const isc::dns::Name& name, bool recursive) {
-    (void)name;
-    (void)recursive;
-    isc_throw(isc::NotImplemented, "not completed yet! please implement me");
+    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_FINDNSEC3).arg(name).
+        arg(recursive ? "recursive" : "non-recursive");
+
+    uint8_t labels_buf[LabelSequence::MAX_SERIALIZED_LENGTH];
+    const LabelSequence origin_ls(zone_data_.getOriginNode()->
+                                  getAbsoluteLabels(labels_buf));
+    const LabelSequence name_ls(name);
+
+    if (!zone_data_.isNSEC3Signed()) {
+        isc_throw(DataSourceError,
+                  "findNSEC3 attempt for non NSEC3 signed zone: " <<
+                  origin_ls << "/" << getClass());
+    }
+
+    const NSEC3Data* nsec3_data = zone_data_.getNSEC3Data();
+    // This would be a programming mistake, as ZoneData::isNSEC3Signed()
+    // should check this.
+    assert(nsec3_data != NULL);
+
+    const ZoneTree& tree = nsec3_data->getNSEC3Tree();
+    if (tree.getNodeCount() == 0) {
+        isc_throw(DataSourceError,
+                  "findNSEC3 attempt but zone has no NSEC3 RRs: " <<
+                  origin_ls << "/" << getClass());
+    }
+
+    const NameComparisonResult cmp_result = name_ls.compare(origin_ls);
+    if (cmp_result.getRelation() != NameComparisonResult::EQUAL &&
+        cmp_result.getRelation() != NameComparisonResult::SUBDOMAIN) {
+        isc_throw(OutOfZone, "findNSEC3 attempt for out-of-zone name: "
+                  << name_ls << ", zone: " << origin_ls << "/"
+                  << getClass());
+    }
+
+    // Convenient shortcuts
+    const unsigned int olabels = origin_ls.getLabelCount();
+    const unsigned int qlabels = name.getLabelCount();
+    // placeholder of the next closer proof
+    const ZoneNode* covering_node(NULL);
+
+    // Now we'll first look up the origin node and initialize orig_chain
+    // with it.
+    ZoneChain orig_chain;
+    const ZoneNode* node(NULL);
+    ZoneTree::Result result =
+         tree.find<void*>(origin_ls, &node, orig_chain, NULL, NULL);
+    if (result != ZoneTree::EXACTMATCH) {
+        // If the origin node doesn't exist, simply fail.
+        isc_throw(DataSourceError,
+                  "findNSEC3 attempt but zone has no NSEC3 RRs: " <<
+                  origin_ls << "/" << getClass());
+    }
+
+    const boost::scoped_ptr<NSEC3Hash> hash
+        (NSEC3Hash::create(nsec3_data->hashalg,
+                           nsec3_data->iterations,
+                           nsec3_data->getSaltData(),
+                           nsec3_data->getSaltLen()));
+
+    // Examine all names from the query name to the origin name, stripping
+    // the deepest label one by one, until we find a name that has a matching
+    // NSEC3 hash.
+    for (unsigned int labels = qlabels; labels >= olabels; --labels) {
+        const Name& hname = (labels == qlabels ?
+                             name : name.split(qlabels - labels, labels));
+        const std::string hlabel = hash->calculate(hname);
+
+        LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_FINDNSEC3_TRYHASH).
+            arg(name).arg(labels).arg(hlabel);
+
+        node = NULL;
+        ZoneChain chain(orig_chain);
+
+        // Now, make a label sequence relative to the origin.
+        const Name hlabel_name(hlabel);
+        LabelSequence hlabel_ls(hlabel_name);
+        // Remove trailing '.' making it relative
+        hlabel_ls.stripRight(1);
+
+        // Find hlabel relative to the orig_chain.
+        result = tree.find<void*>(hlabel_ls, &node, chain, NULL, NULL);
+        if (result == ZoneTree::EXACTMATCH) {
+            // We found an exact match.
+            ConstRRsetPtr closest = createNSEC3RRset(node, getClass());
+            ConstRRsetPtr next;
+            if (covering_node != NULL) {
+                next = createNSEC3RRset(covering_node, getClass());
+            }
+
+            LOG_DEBUG(logger, DBG_TRACE_BASIC,
+                      DATASRC_MEM_FINDNSEC3_MATCH).arg(name).arg(labels).
+                arg(*closest);
+
+            return (FindNSEC3Result(true, labels, closest, next));
+        } else {
+            while ((covering_node = tree.previousNode(chain)) != NULL &&
+                   covering_node->isEmpty()) {
+                ;
+            }
+            if (covering_node == NULL) {
+                covering_node = tree.largestNode();
+            }
+
+            if (!recursive) {   // in non recursive mode, we are done.
+                ConstRRsetPtr closest;
+                if (covering_node != NULL) {
+                    closest = createNSEC3RRset(covering_node, getClass());
+
+                    LOG_DEBUG(logger, DBG_TRACE_BASIC,
+                              DATASRC_MEM_FINDNSEC3_COVER).
+                        arg(name).arg(*closest);
+                }
+
+                return (FindNSEC3Result(false, labels,
+                                        closest, ConstRRsetPtr()));
+            }
+        }
+    }
+
+    isc_throw(DataSourceError, "recursive findNSEC3 mode didn't stop, likely "
+              "a broken NSEC3 zone: " << getOrigin() << "/"
+              << getClass());
+}
+
+Name
+InMemoryZoneFinder::getOrigin() const {
+    size_t data_len;
+    const uint8_t* data;
+
+    // Normally the label sequence of the origin node should be absolute,
+    // in which case we can simply generate the origin name from the labels.
+    const LabelSequence node_labels = zone_data_.getOriginNode()->getLabels();
+    if (node_labels.isAbsolute()) {
+        data = node_labels.getData(&data_len);
+    } else {
+        // In future we may allow adding out-of-zone names in the zone tree.
+        // For example, to hold out-of-zone NS names so we can establish a
+        // shortcut link to them as an optimization.  If and when that happens
+        // the origin node may not have an absolute label (consider the zone
+        // is example.org and we add ns.noexample.org).  In that case
+        // we first need to construct the absolute label sequence and then
+        // construct the name.
+        uint8_t labels_buf[LabelSequence::MAX_SERIALIZED_LENGTH];
+        const LabelSequence name_labels =
+            zone_data_.getOriginNode()->getAbsoluteLabels(labels_buf);
+        data = name_labels.getData(&data_len);
+    }
+    util::InputBuffer buffer(data, data_len);
+    return (Name(buffer));
 }
 
 } // namespace memory
diff --git a/src/lib/datasrc/memory/zone_finder.h b/src/lib/datasrc/memory/zone_finder.h
index 8f2c687..85e21c3 100644
--- a/src/lib/datasrc/memory/zone_finder.h
+++ b/src/lib/datasrc/memory/zone_finder.h
@@ -23,30 +23,15 @@
 #include <dns/rrset.h>
 #include <dns/rrtype.h>
 
+#include <string>
+
 namespace isc {
 namespace datasrc {
 namespace memory {
-
-class ZoneFinderResultContext {
-public:
-    /// \brief Constructor
-    ///
-    /// The first three parameters correspond to those of
-    /// ZoneFinder::ResultContext.  If node is non NULL, it specifies the
-    /// found RBNode in the search.
-    ZoneFinderResultContext(ZoneFinder::Result code_param,
-                            TreeNodeRRsetPtr rrset_param,
-                            ZoneFinder::FindResultFlags flags_param,
-                            const ZoneNode* node) :
-        code(code_param), rrset(rrset_param), flags(flags_param),
-        found_node(node)
-    {}
-
-    const ZoneFinder::Result code;
-    const TreeNodeRRsetPtr rrset;
-    const ZoneFinder::FindResultFlags flags;
-    const ZoneNode* const found_node;
-};
+namespace internal {
+// intermediate result context, only used in the zone finder implementation.
+class ZoneFinderResultContext;
+}
 
 /// A derived zone finder class intended to be used with the memory data
 /// source, using ZoneData for its contents.
@@ -92,16 +77,13 @@ public:
     findNSEC3(const isc::dns::Name& name, bool recursive);
 
     /// \brief Returns the origin of the zone.
-    virtual isc::dns::Name getOrigin() const {
-        return zone_data_.getOriginNode()->getName();
-    }
+    virtual isc::dns::Name getOrigin() const;
 
     /// \brief Returns the RR class of the zone.
     virtual isc::dns::RRClass getClass() const {
-        return rrclass_;
+        return (rrclass_);
     }
 
-
 private:
     /// \brief In-memory version of finder context.
     ///
@@ -110,7 +92,7 @@ private:
     class Context;
 
     /// Actual implementation for both find() and findAll()
-    ZoneFinderResultContext find_internal(
+    internal::ZoneFinderResultContext find_internal(
         const isc::dns::Name& name,
         const isc::dns::RRType& type,
         std::vector<isc::dns::ConstRRsetPtr>* target,
@@ -118,7 +100,7 @@ private:
         FIND_DEFAULT);
 
     const ZoneData& zone_data_;
-    const isc::dns::RRClass& rrclass_;
+    const isc::dns::RRClass rrclass_;
 };
 
 } // namespace memory
diff --git a/src/lib/datasrc/tests/Makefile.am b/src/lib/datasrc/tests/Makefile.am
index 9ff67bd..d2049f1 100644
--- a/src/lib/datasrc/tests/Makefile.am
+++ b/src/lib/datasrc/tests/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = testdata
+SUBDIRS = . memory testdata
 
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS += -I$(top_builddir)/src/lib/dns -I$(top_srcdir)/src/lib/dns
diff --git a/src/lib/datasrc/tests/client_list_unittest.cc b/src/lib/datasrc/tests/client_list_unittest.cc
index 3ca906b..d995d5c 100644
--- a/src/lib/datasrc/tests/client_list_unittest.cc
+++ b/src/lib/datasrc/tests/client_list_unittest.cc
@@ -12,11 +12,14 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <util/memory_segment_local.h>
+
 #include <datasrc/client_list.h>
 #include <datasrc/client.h>
 #include <datasrc/iterator.h>
 #include <datasrc/data_source.h>
-#include <datasrc/memory_datasrc.h>
+#include <datasrc/memory/memory_client.h>
+#include <datasrc/memory/zone_finder.h>
 
 #include <dns/rrclass.h>
 #include <dns/rrttl.h>
@@ -28,6 +31,8 @@
 #include <fstream>
 
 using namespace isc::datasrc;
+using isc::datasrc::memory::InMemoryClient;
+using isc::datasrc::memory::InMemoryZoneFinder;
 using namespace isc::data;
 using namespace isc::dns;
 using namespace boost;
@@ -67,35 +72,47 @@ public:
     };
     class Iterator : public ZoneIterator {
     public:
-        Iterator(const Name& origin) :
+        Iterator(const Name& origin, bool include_ns) :
             origin_(origin),
-            finished_(false),
-            soa_(new RRset(origin_, RRClass::IN(), RRType::SOA(), RRTTL(3600)))
+            soa_(new RRset(origin_, RRClass::IN(), RRType::SOA(),
+                           RRTTL(3600)))
         {
             // The RData here is bogus, but it is not used to anything. There
             // just needs to be some.
             soa_->addRdata(rdata::generic::SOA(Name::ROOT_NAME(),
                                                Name::ROOT_NAME(),
                                                0, 0, 0, 0, 0));
+            rrsets_.push_back(soa_);
+
+            if (include_ns) {
+                ns_.reset(new RRset(origin_, RRClass::IN(), RRType::NS(),
+                                    RRTTL(3600)));
+                ns_->addRdata(rdata::generic::NS(Name::ROOT_NAME()));
+                rrsets_.push_back(ns_);
+            }
+            rrsets_.push_back(ConstRRsetPtr());
+
+            it_ = rrsets_.begin();
         }
         virtual isc::dns::ConstRRsetPtr getNextRRset() {
-            if (finished_) {
-                return (ConstRRsetPtr());
-            } else {
-                finished_ = true;
-                return (soa_);
-            }
+            ConstRRsetPtr result = *it_;
+            ++it_;
+            return (result);
         }
         virtual isc::dns::ConstRRsetPtr getSOA() const {
             return (soa_);
         }
     private:
         const Name origin_;
-        bool finished_;
-        const isc::dns::RRsetPtr soa_;
+        const RRsetPtr soa_;
+        RRsetPtr ns_;
+        std::vector<ConstRRsetPtr> rrsets_;
+        std::vector<ConstRRsetPtr>::const_iterator it_;
     };
     // Constructor from a list of zones.
-    MockDataSourceClient(const char* zone_names[]) {
+    MockDataSourceClient(const char* zone_names[]) :
+        have_ns_(true), use_baditerator_(true)
+    {
         for (const char** zone(zone_names); *zone; ++zone) {
             zones.insert(Name(*zone));
         }
@@ -105,7 +122,8 @@ public:
     MockDataSourceClient(const string& type,
                          const ConstElementPtr& configuration) :
         type_(type),
-        configuration_(configuration)
+        configuration_(configuration),
+        have_ns_(true), use_baditerator_(true)
     {
         EXPECT_NE("MasterFiles", type) << "MasterFiles is a special case "
             "and it never should be created as a data source client";
@@ -146,23 +164,27 @@ public:
         isc_throw(isc::NotImplemented, "Not implemented");
     }
     virtual ZoneIteratorPtr getIterator(const Name& name, bool) const {
-        if (name == Name("noiter.org")) {
+        if (use_baditerator_ && name == Name("noiter.org")) {
             isc_throw(isc::NotImplemented, "Asked not to be implemented");
-        } else if (name == Name("null.org")) {
+        } else if (use_baditerator_ && name == Name("null.org")) {
             return (ZoneIteratorPtr());
         } else {
             FindResult result(findZone(name));
             if (result.code == isc::datasrc::result::SUCCESS) {
-                return (ZoneIteratorPtr(new Iterator(name)));
+                return (ZoneIteratorPtr(new Iterator(name, have_ns_)));
             } else {
                 isc_throw(DataSourceError, "No such zone");
             }
         }
     }
+    void disableNS() { have_ns_ = false; }
+    void disableBadIterator() { use_baditerator_ = false; }
     const string type_;
     const ConstElementPtr configuration_;
 private:
     set<Name> zones;
+    bool have_ns_; // control the iterator behavior wrt whether to include NS
+    bool use_baditerator_; // whether to use bogus zone iterators for tests
 };
 
 
@@ -220,8 +242,9 @@ const size_t ds_count = (sizeof(ds_zones) / sizeof(*ds_zones));
 class ListTest : public ::testing::Test {
 public:
     ListTest() :
+        rrclass_(RRClass::IN()),
         // The empty list corresponds to a list with no elements inside
-        list_(new TestedList(RRClass::IN())),
+        list_(new TestedList(rrclass_)),
         config_elem_(Element::fromJSON("["
             "{"
             "   \"type\": \"test_type\","
@@ -238,28 +261,35 @@ public:
             shared_ptr<MockDataSourceClient>
                 ds(new MockDataSourceClient(ds_zones[i]));
             ds_.push_back(ds);
-            ds_info_.push_back(ConfigurableClientList::DataSourceInfo(ds.get(),
-                DataSourceClientContainerPtr(), false));
+            ds_info_.push_back(ConfigurableClientList::DataSourceInfo(
+                                   ds.get(), DataSourceClientContainerPtr(),
+                                   false, rrclass_, mem_sgmt_));
         }
     }
-    void prepareCache(size_t index, const Name& zone, bool prefill = false) {
-        const shared_ptr<InMemoryClient> cache(new InMemoryClient());
-        const shared_ptr<InMemoryZoneFinder>
-            finder(new InMemoryZoneFinder(RRClass::IN(), zone));
-        if (prefill) {
-            RRsetPtr soa(new RRset(zone, RRClass::IN(), RRType::SOA(),
-                                   RRTTL(3600)));
-            // The RData here is bogus, but it is not used to anything. There
-            // just needs to be some.
-            soa->addRdata(rdata::generic::SOA(Name::ROOT_NAME(),
-                                              Name::ROOT_NAME(),
-                                              0, 0, 0, 0, 0));
-            finder->add(soa);
-        }
-        // If we don't do prefill, we leave the zone empty. This way,
-        // we can check when it was reloaded.
-        cache->addZone(finder);
-        list_->getDataSources()[index].cache_ = cache;
+
+    // Install a "fake" cached zone using a temporary underlying data source
+    // client.
+    void prepareCache(size_t index, const Name& zone) {
+        // Prepare the temporary data source client
+        const char* zones[2];
+        const std::string zonename_txt = zone.toText();
+        zones[0] = zonename_txt.c_str();
+        zones[1] = NULL;
+        MockDataSourceClient mock_client(zones);
+        // Disable some default features of the mock to distinguish the
+        // temporary case from normal case.
+        mock_client.disableNS();
+        mock_client.disableBadIterator();
+
+        // Create cache from the temporary data source, and push it to the
+        // client list.
+        const shared_ptr<InMemoryClient> cache(new InMemoryClient(mem_sgmt_,
+                                                                  rrclass_));
+        cache->load(zone, *mock_client.getIterator(zone, false));
+
+        ConfigurableClientList::DataSourceInfo& dsrc_info =
+                list_->getDataSources()[index];
+        dsrc_info.cache_ = cache;
     }
     // Check the positive result is as we expect it.
     void positiveResult(const ClientList::FindResult& result,
@@ -331,6 +361,8 @@ public:
         EXPECT_EQ(cache, list_->getDataSources()[index].cache_ !=
                   shared_ptr<InMemoryClient>());
     }
+    const RRClass rrclass_;
+    isc::util::MemorySegmentLocal mem_sgmt_;
     shared_ptr<TestedList> list_;
     const ClientList::FindResult negative_result_;
     vector<shared_ptr<MockDataSourceClient> > ds_;
@@ -815,39 +847,38 @@ TEST_F(ListTest, BadMasterFile) {
 // Test we can reload a zone
 TEST_F(ListTest, reloadSuccess) {
     list_->configure(config_elem_zones_, true);
-    Name name("example.org");
+    const Name name("example.org");
     prepareCache(0, name);
-    // Not there yet. It would be NXDOMAIN, but it is in apex and
-    // it returns NXRRSET instead.
+    // The cache currently contains a tweaked version of zone, which doesn't
+    // have apex NS.  So the lookup should result in NXRRSET.
     EXPECT_EQ(ZoneFinder::NXRRSET,
-              list_->find(name).finder_->find(name, RRType::SOA())->code);
-    // Now reload. It should be there now.
+              list_->find(name).finder_->find(name, RRType::NS())->code);
+    // Now reload the full zone. It should be there now.
     EXPECT_EQ(ConfigurableClientList::ZONE_RELOADED, list_->reload(name));
     EXPECT_EQ(ZoneFinder::SUCCESS,
-              list_->find(name).finder_->find(name, RRType::SOA())->code);
+              list_->find(name).finder_->find(name, RRType::NS())->code);
 }
 
 // The cache is not enabled. The load should be rejected.
 TEST_F(ListTest, reloadNotEnabled) {
     list_->configure(config_elem_zones_, false);
-    Name name("example.org");
+    const Name name("example.org");
     // We put the cache in even when not enabled. This won't confuse the thing.
     prepareCache(0, name);
-    // Not there yet. It would be NXDOMAIN, but it is in apex and
-    // it returns NXRRSET instead.
+    // See the reloadSuccess test.  This should result in NXRRSET.
     EXPECT_EQ(ZoneFinder::NXRRSET,
-              list_->find(name).finder_->find(name, RRType::SOA())->code);
+              list_->find(name).finder_->find(name, RRType::NS())->code);
     // Now reload. It should reject it.
     EXPECT_EQ(ConfigurableClientList::CACHE_DISABLED, list_->reload(name));
     // Nothing changed here
     EXPECT_EQ(ZoneFinder::NXRRSET,
-              list_->find(name).finder_->find(name, RRType::SOA())->code);
+              list_->find(name).finder_->find(name, RRType::NS())->code);
 }
 
 // Test several cases when the zone does not exist
 TEST_F(ListTest, reloadNoSuchZone) {
     list_->configure(config_elem_zones_, true);
-    Name name("example.org");
+    const Name name("example.org");
     // We put the cache in even when not enabled. This won't confuse the
     // reload method, as that one looks at the real state of things, not
     // at the configuration.
@@ -867,27 +898,27 @@ TEST_F(ListTest, reloadNoSuchZone) {
               list_->find(Name("example.cz")).dsrc_client_);
     EXPECT_EQ(static_cast<isc::datasrc::DataSourceClient*>(NULL),
               list_->find(Name("sub.example.com"), true).dsrc_client_);
-    // Not reloaded
+    // Not reloaded, so NS shouldn't be visible yet.
     EXPECT_EQ(ZoneFinder::NXRRSET,
               list_->find(Name("example.com")).finder_->
-              find(Name("example.com"), RRType::SOA())->code);
+              find(Name("example.com"), RRType::NS())->code);
 }
 
 // Check we gracefuly throw an exception when a zone disappeared in
 // the underlying data source when we want to reload it
 TEST_F(ListTest, reloadZoneGone) {
     list_->configure(config_elem_, true);
-    Name name("example.org");
+    const Name name("example.org");
     // We put in a cache for non-existant zone. This emulates being loaded
     // and then the zone disappearing. We prefill the cache, so we can check
     // it.
-    prepareCache(0, name, true);
-    // The zone contains something
+    prepareCache(0, name);
+    // The (cached) zone contains zone's SOA
     EXPECT_EQ(ZoneFinder::SUCCESS,
               list_->find(name).finder_->find(name, RRType::SOA())->code);
     // The zone is not there, so abort the reload.
     EXPECT_THROW(list_->reload(name), DataSourceError);
-    // The zone is not hurt.
+    // The (cached) zone is not hurt.
     EXPECT_EQ(ZoneFinder::SUCCESS,
               list_->find(name).finder_->find(name, RRType::SOA())->code);
 }
@@ -895,8 +926,8 @@ TEST_F(ListTest, reloadZoneGone) {
 // The underlying data source throws. Check we don't modify the state.
 TEST_F(ListTest, reloadZoneThrow) {
     list_->configure(config_elem_zones_, true);
-    Name name("noiter.org");
-    prepareCache(0, name, true);
+    const Name name("noiter.org");
+    prepareCache(0, name);
     // The zone contains stuff now
     EXPECT_EQ(ZoneFinder::SUCCESS,
               list_->find(name).finder_->find(name, RRType::SOA())->code);
@@ -909,8 +940,8 @@ TEST_F(ListTest, reloadZoneThrow) {
 
 TEST_F(ListTest, reloadNullIterator) {
     list_->configure(config_elem_zones_, true);
-    Name name("null.org");
-    prepareCache(0, name, true);
+    const Name name("null.org");
+    prepareCache(0, name);
     // The zone contains stuff now
     EXPECT_EQ(ZoneFinder::SUCCESS,
               list_->find(name).finder_->find(name, RRType::SOA())->code);
diff --git a/src/lib/datasrc/tests/faked_nsec3.cc b/src/lib/datasrc/tests/faked_nsec3.cc
index b702d28..f53fbd7 100644
--- a/src/lib/datasrc/tests/faked_nsec3.cc
+++ b/src/lib/datasrc/tests/faked_nsec3.cc
@@ -67,6 +67,17 @@ public:
             "00000000000000000000000000000000";
         map_[Name("largest.example.org")] =
             "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU";
+
+        // These are used by the findNSEC3Walk test.
+        map_[Name("n0.example.org")] = "00000000000000000000000000000000";
+        map_[Name("n1.example.org")] = "01UDEMVP1J2F7EG6JEBPS17VP3N8I58H";
+        map_[Name("n2.example.org")] = "02UDEMVP1J2F7EG6JEBPS17VP3N8I58H";
+        map_[Name("n3.example.org")] = "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
+        map_[Name("n4.example.org")] = "11111111111111111111111111111111";
+        map_[Name("n5.example.org")] = "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR";
+        map_[Name("n6.example.org")] = "44444444444444444444444444444444";
+        map_[Name("n7.example.org")] = "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN";
+        map_[Name("n8.example.org")] = "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ";
     }
     virtual string calculate(const Name& name) const {
         const NSEC3HashMap::const_iterator found = map_.find(name);
@@ -94,6 +105,12 @@ NSEC3Hash* TestNSEC3HashCreator::create(const rdata::generic::NSEC3&) const {
     return (new TestNSEC3Hash);
 }
 
+NSEC3Hash* TestNSEC3HashCreator::create(uint8_t, uint16_t,
+                                        const uint8_t*, size_t) const
+{
+    return (new TestNSEC3Hash);
+}
+
 void
 findNSEC3Check(bool expected_matched, uint8_t expected_labels,
                const string& expected_closest,
diff --git a/src/lib/datasrc/tests/faked_nsec3.h b/src/lib/datasrc/tests/faked_nsec3.h
index 8c1857c..26a7b8d 100644
--- a/src/lib/datasrc/tests/faked_nsec3.h
+++ b/src/lib/datasrc/tests/faked_nsec3.h
@@ -57,11 +57,15 @@ class TestNSEC3HashCreator : public isc::dns::NSEC3HashCreator {
 private:
     class TestNSEC3Hash;
 public:
+    TestNSEC3HashCreator() {}
     virtual isc::dns::NSEC3Hash* create(const
                                         isc::dns::rdata::generic::NSEC3PARAM&)
         const;
     virtual isc::dns::NSEC3Hash* create(const isc::dns::rdata::generic::NSEC3&)
         const;
+    virtual isc::dns::NSEC3Hash* create(uint8_t, uint16_t,
+                                        const uint8_t*, size_t)
+        const;
 };
 
 // Check the result against expected values. It directly calls EXPECT_ macros
diff --git a/src/lib/datasrc/tests/memory/.gitignore b/src/lib/datasrc/tests/memory/.gitignore
new file mode 100644
index 0000000..d6d1ec8
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/.gitignore
@@ -0,0 +1 @@
+/run_unittests
diff --git a/src/lib/datasrc/tests/memory/Makefile.am b/src/lib/datasrc/tests/memory/Makefile.am
new file mode 100644
index 0000000..00d5594
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/Makefile.am
@@ -0,0 +1,49 @@
+SUBDIRS = testdata .
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += -I$(top_builddir)/src/lib/dns -I$(top_srcdir)/src/lib/dns
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(abs_srcdir)/testdata\"
+
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+CLEANFILES = *.gcno *.gcda
+
+TESTS_ENVIRONMENT = \
+	$(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
+
+TESTS =
+if HAVE_GTEST
+TESTS += run_unittests
+
+run_unittests_SOURCES = run_unittests.cc
+run_unittests_SOURCES += rdata_serialization_unittest.cc
+run_unittests_SOURCES += rdataset_unittest.cc
+run_unittests_SOURCES += domaintree_unittest.cc
+run_unittests_SOURCES += treenode_rrset_unittest.cc
+run_unittests_SOURCES += zone_table_unittest.cc
+run_unittests_SOURCES += zone_data_unittest.cc
+run_unittests_SOURCES += zone_finder_unittest.cc
+run_unittests_SOURCES += ../../tests/faked_nsec3.h ../../tests/faked_nsec3.cc
+run_unittests_SOURCES += memory_segment_test.h
+run_unittests_SOURCES += segment_object_holder_unittest.cc
+run_unittests_SOURCES += memory_client_unittest.cc
+
+run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
+run_unittests_LDFLAGS  = $(AM_LDFLAGS)  $(GTEST_LDFLAGS)
+
+run_unittests_LDADD = $(top_builddir)/src/lib/datasrc/libb10-datasrc.la
+run_unittests_LDADD += $(top_builddir)/src/lib/dns/libb10-dns++.la
+run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
+run_unittests_LDADD += $(top_builddir)/src/lib/util/libb10-util.la
+run_unittests_LDADD += $(top_builddir)/src/lib/testutils/libb10-testutils.la
+run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
+run_unittests_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
+run_unittests_LDADD += $(GTEST_LDADD)
+endif
+
+noinst_PROGRAMS = $(TESTS)
diff --git a/src/lib/datasrc/tests/memory/domaintree_unittest.cc b/src/lib/datasrc/tests/memory/domaintree_unittest.cc
new file mode 100644
index 0000000..cb16e02
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/domaintree_unittest.cc
@@ -0,0 +1,1292 @@
+// Copyright (C) 2010  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 <gtest/gtest.h>
+
+#include <exceptions/exceptions.h>
+
+#include <util/memory_segment_local.h>
+
+#include <dns/name.h>
+#include <dns/rrclass.h>
+#include <dns/rrset.h>
+#include <dns/rrtype.h>
+#include <dns/rrttl.h>
+
+#include <datasrc/memory/domaintree.h>
+
+#include <dns/tests/unittest_util.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dns;
+using isc::UnitTestUtil;
+using namespace isc::datasrc::memory;
+
+// XXX: some compilers cannot find class static constants used in
+// EXPECT_xxx macros, for which we need an explicit empty definition.
+const size_t Name::MAX_LABELS;
+
+/* The initial structure of dtree
+ *
+ *             .
+ *             |
+ *             b
+ *           /   \
+ *          a    d.e.f
+ *              /  |   \
+ *             c   |    g.h
+ *                 |     |
+ *                w.y    i
+ *              /  |  \   \
+ *             x   |   z   k
+ *                 |   |
+ *                 p   j
+ *               /   \
+ *              o     q
+ */
+
+namespace {
+
+void deleteData(int* i) {
+    delete i;
+}
+
+typedef DomainTree<int> TestDomainTree;
+typedef DomainTreeNode<int> TestDomainTreeNode;
+typedef DomainTreeNodeChain<int> TestDomainTreeNodeChain;
+
+class TreeHolder {
+public:
+    TreeHolder(util::MemorySegment& mem_sgmt, TestDomainTree* tree) :
+        mem_sgmt_(mem_sgmt), tree_(tree)
+    {}
+    ~TreeHolder() {
+        TestDomainTree::destroy(mem_sgmt_, tree_, deleteData);
+    }
+    TestDomainTree* get() { return (tree_); }
+private:
+    util::MemorySegment& mem_sgmt_;
+    TestDomainTree* tree_;
+};
+
+class DomainTreeTest : public::testing::Test {
+protected:
+    DomainTreeTest() :
+        dtree_holder_(mem_sgmt_, TestDomainTree::create(mem_sgmt_)),
+        dtree_expose_empty_node_holder_(mem_sgmt_,
+                                         TestDomainTree::create(mem_sgmt_, true)),
+        dtree(*dtree_holder_.get()),
+        dtree_expose_empty_node(*dtree_expose_empty_node_holder_.get()),
+        cdtnode(NULL)
+    {
+        const char* const domain_names[] = {
+            "c", "b", "a", "x.d.e.f", "z.d.e.f", "g.h", "i.g.h", "o.w.y.d.e.f",
+            "j.z.d.e.f", "p.w.y.d.e.f", "q.w.y.d.e.f", "k.g.h"};
+        int name_count = sizeof(domain_names) / sizeof(domain_names[0]);
+        for (int i = 0; i < name_count; ++i) {
+            dtree.insert(mem_sgmt_, Name(domain_names[i]), &dtnode);
+            // Check the node doesn't have any data initially.
+            EXPECT_EQ(static_cast<int*>(NULL),
+                      dtnode->setData(new int(i + 1)));
+
+            dtree_expose_empty_node.insert(mem_sgmt_, Name(domain_names[i]),
+                                            &dtnode);
+            EXPECT_EQ(static_cast<int*>(NULL), dtnode->setData(new int(i + 1)));
+        }
+    }
+
+    util::MemorySegmentLocal mem_sgmt_;
+    TreeHolder dtree_holder_;
+    TreeHolder dtree_expose_empty_node_holder_;
+    TestDomainTree& dtree;
+    TestDomainTree& dtree_expose_empty_node;
+    TestDomainTreeNode* dtnode;
+    const TestDomainTreeNode* cdtnode;
+    uint8_t buf[LabelSequence::MAX_SERIALIZED_LENGTH];
+};
+
+TEST_F(DomainTreeTest, nodeCount) {
+    EXPECT_EQ(15, dtree.getNodeCount());
+
+    // Delete all nodes, then the count should be set to 0.  This also tests
+    // the behavior of deleteAllNodes().
+    dtree.deleteAllNodes(mem_sgmt_, deleteData);
+    EXPECT_EQ(0, dtree.getNodeCount());
+}
+
+TEST_F(DomainTreeTest, setGetData) {
+    // set new data to an existing node.  It should have some data.
+    int* newdata = new int(11);
+    int* olddata = dtnode->setData(newdata);
+    EXPECT_NE(static_cast<int*>(NULL), olddata);
+    deleteData(olddata);
+    EXPECT_EQ(11, *(dtnode->getData()));
+
+    // clear the node.  we should get the new data back we just passed.
+    olddata = dtnode->setData(NULL);
+    EXPECT_EQ(newdata, olddata);
+    deleteData(olddata);
+}
+
+TEST_F(DomainTreeTest, insertNames) {
+    EXPECT_EQ(TestDomainTree::ALREADYEXISTS, dtree.insert(mem_sgmt_,
+                                                        Name("d.e.f"),
+                                                        &dtnode));
+    EXPECT_EQ(Name("d.e.f"), dtnode->getName());
+    EXPECT_EQ(15, dtree.getNodeCount());
+
+    // insert not exist node
+    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_, Name("0"),
+                                                  &dtnode));
+    EXPECT_EQ(Name("0"), dtnode->getName());
+    EXPECT_EQ(16, dtree.getNodeCount());
+
+    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_,
+                                                  Name("example.com"),
+                                                  &dtnode));
+    EXPECT_EQ(17, dtree.getNodeCount());
+    // add data to it; also make sure it doesn't have data right now
+    // (otherwise it would leak)
+    EXPECT_EQ(static_cast<int*>(NULL), dtnode->setData(new int(12)));
+
+    // return ALREADYEXISTS, since node "example.com" already has
+    // been explicitly inserted
+    EXPECT_EQ(TestDomainTree::ALREADYEXISTS, dtree.insert(mem_sgmt_,
+                                                        Name("example.com"),
+                                                        &dtnode));
+    EXPECT_EQ(17, dtree.getNodeCount());
+
+    // split the node "d.e.f"
+    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_, Name("k.e.f"),
+                                                  &dtnode));
+    EXPECT_EQ(Name("k"), dtnode->getName());
+    EXPECT_EQ(19, dtree.getNodeCount());
+
+    // split the node "g.h"
+    EXPECT_EQ(TestDomainTree::ALREADYEXISTS, dtree.insert(mem_sgmt_, Name("h"),
+                                                        &dtnode));
+    EXPECT_EQ(Name("h"), dtnode->getName());
+    EXPECT_EQ(20, dtree.getNodeCount());
+
+    // add child domain
+    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_,
+                                                  Name("m.p.w.y.d.e.f"),
+                                                  &dtnode));
+    EXPECT_EQ(Name("m"), dtnode->getName());
+    EXPECT_EQ(21, dtree.getNodeCount());
+    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_,
+                                                  Name("n.p.w.y.d.e.f"),
+                                                  &dtnode));
+    EXPECT_EQ(Name("n"), dtnode->getName());
+    EXPECT_EQ(22, dtree.getNodeCount());
+
+    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_, Name("l.a"),
+                                                  &dtnode));
+    EXPECT_EQ(Name("l"), dtnode->getName());
+    EXPECT_EQ(23, dtree.getNodeCount());
+
+    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_, Name("r.d.e.f"),
+                                                  &dtnode));
+    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_, Name("s.d.e.f"),
+                                                  &dtnode));
+    EXPECT_EQ(25, dtree.getNodeCount());
+
+    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_,
+                                                  Name("h.w.y.d.e.f"),
+                                                  &dtnode));
+
+    // add more nodes one by one to cover leftRotate and rightRotate
+    EXPECT_EQ(TestDomainTree::ALREADYEXISTS, dtree.insert(mem_sgmt_, Name("f"),
+                                                        &dtnode));
+    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_, Name("m"),
+                                                  &dtnode));
+    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_, Name("nm"),
+                                                  &dtnode));
+    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_, Name("om"),
+                                                  &dtnode));
+    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_, Name("k"),
+                                                  &dtnode));
+    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_, Name("l"),
+                                                  &dtnode));
+    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_, Name("fe"),
+                                                  &dtnode));
+    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_, Name("ge"),
+                                                  &dtnode));
+    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_, Name("i"),
+                                                  &dtnode));
+    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_, Name("ae"),
+                                                  &dtnode));
+    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_, Name("n"),
+                                                  &dtnode));
+}
+
+TEST_F(DomainTreeTest, subTreeRoot) {
+    // This is a testcase for a particular issue that went unchecked in
+    // #2089's implementation, but was fixed in #2092. The issue was
+    // that when a node was fissioned, FLAG_SUBTREE_ROOT was not being
+    // copied correctly.
+
+    EXPECT_EQ(TestDomainTree::ALREADYEXISTS,
+              dtree_expose_empty_node.insert(mem_sgmt_, Name("d.e.f"),
+                                              &dtnode));
+    EXPECT_EQ(TestDomainTree::SUCCESS,
+              dtree_expose_empty_node.insert(mem_sgmt_, Name("0"),
+                                              &dtnode));
+    EXPECT_EQ(TestDomainTree::SUCCESS,
+              dtree_expose_empty_node.insert(mem_sgmt_, Name("example.com"),
+                                              &dtnode));
+    EXPECT_EQ(TestDomainTree::ALREADYEXISTS,
+              dtree_expose_empty_node.insert(mem_sgmt_, Name("example.com"),
+                                              &dtnode));
+    EXPECT_EQ(TestDomainTree::SUCCESS,
+              dtree_expose_empty_node.insert(mem_sgmt_, Name("k.e.f"),
+                                              &dtnode));
+
+    // "g.h" is not a subtree root
+    EXPECT_EQ(TestDomainTree::EXACTMATCH,
+              dtree_expose_empty_node.find(Name("g.h"), &dtnode));
+    EXPECT_FALSE(dtnode->getFlag(TestDomainTreeNode::FLAG_SUBTREE_ROOT));
+
+    // fission the node "g.h"
+    EXPECT_EQ(TestDomainTree::ALREADYEXISTS,
+              dtree_expose_empty_node.insert(mem_sgmt_, Name("h"),
+                                              &dtnode));
+
+    // the node "h" (h.down_ -> "g") should not be a subtree root. "g"
+    // should be a subtree root.
+    EXPECT_FALSE(dtnode->getFlag(TestDomainTreeNode::FLAG_SUBTREE_ROOT));
+
+    // "g.h" should be a subtree root now.
+    EXPECT_EQ(TestDomainTree::EXACTMATCH,
+              dtree_expose_empty_node.find(Name("g.h"), &dtnode));
+    EXPECT_TRUE(dtnode->getFlag(TestDomainTreeNode::FLAG_SUBTREE_ROOT));
+}
+
+TEST_F(DomainTreeTest, additionalNodeFission) {
+    // These are additional nodeFission tests added by #2054's rewrite
+    // of DomainTree::nodeFission(). These test specific corner cases that
+    // are not covered by other tests.
+
+    // Insert "t.0" (which becomes the left child of its parent)
+    EXPECT_EQ(TestDomainTree::SUCCESS,
+              dtree_expose_empty_node.insert(mem_sgmt_, Name("t.0"),
+                                             &dtnode));
+
+    // "t.0" is not a subtree root
+    EXPECT_EQ(TestDomainTree::EXACTMATCH,
+              dtree_expose_empty_node.find(Name("t.0"), &dtnode));
+    EXPECT_FALSE(dtnode->getFlag(TestDomainTreeNode::FLAG_SUBTREE_ROOT));
+
+    // fission the node "t.0"
+    EXPECT_EQ(TestDomainTree::ALREADYEXISTS,
+              dtree_expose_empty_node.insert(mem_sgmt_, Name("0"),
+                                             &dtnode));
+
+    // the node "0" ("0".down_ -> "t") should not be a subtree root. "t"
+    // should be a subtree root.
+    EXPECT_FALSE(dtnode->getFlag(TestDomainTreeNode::FLAG_SUBTREE_ROOT));
+
+    // "t.0" should be a subtree root now.
+    EXPECT_EQ(TestDomainTree::EXACTMATCH,
+              dtree_expose_empty_node.find(Name("t.0"), &dtnode));
+    EXPECT_TRUE(dtnode->getFlag(TestDomainTreeNode::FLAG_SUBTREE_ROOT));
+}
+
+TEST_F(DomainTreeTest, findName) {
+    // find const dtnode
+    // exact match
+    EXPECT_EQ(TestDomainTree::EXACTMATCH, dtree.find(Name("a"), &cdtnode));
+    EXPECT_EQ(Name("a"), cdtnode->getName());
+
+    // not found
+    EXPECT_EQ(TestDomainTree::NOTFOUND, dtree.find(Name("d.e.f"), &cdtnode));
+    EXPECT_EQ(TestDomainTree::NOTFOUND, dtree.find(Name("y.d.e.f"), &cdtnode));
+    EXPECT_EQ(TestDomainTree::NOTFOUND, dtree.find(Name("x"), &cdtnode));
+    EXPECT_EQ(TestDomainTree::NOTFOUND, dtree.find(Name("m.n"), &cdtnode));
+
+    // if we expose empty node, we can get the empty node created during insert
+    EXPECT_EQ(TestDomainTree::EXACTMATCH,
+              dtree_expose_empty_node.find(Name("d.e.f"), &cdtnode));
+    EXPECT_EQ(TestDomainTree::EXACTMATCH,
+              dtree_expose_empty_node.find(Name("w.y.d.e.f"), &cdtnode));
+
+    // partial match
+    EXPECT_EQ(TestDomainTree::PARTIALMATCH, dtree.find(Name("m.b"), &cdtnode));
+    EXPECT_EQ(Name("b"), cdtnode->getName());
+    EXPECT_EQ(TestDomainTree::PARTIALMATCH,
+              dtree_expose_empty_node.find(Name("m.d.e.f"), &cdtnode));
+
+    // find dtnode
+    EXPECT_EQ(TestDomainTree::EXACTMATCH, dtree.find(Name("q.w.y.d.e.f"),
+                                                   &dtnode));
+    EXPECT_EQ(Name("q"), dtnode->getName());
+}
+
+TEST_F(DomainTreeTest, findError) {
+    // For the version that takes a node chain, the chain must be empty.
+    TestDomainTreeNodeChain chain;
+    EXPECT_EQ(TestDomainTree::EXACTMATCH, dtree.find(Name("a"), &cdtnode,
+                                                   chain));
+    // trying to reuse the same chain.  it should result in an exception.
+    EXPECT_THROW(dtree.find(Name("a"), &cdtnode, chain),
+                 BadValue);
+}
+
+TEST_F(DomainTreeTest, flags) {
+    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt_,
+                                                  Name("flags.example"),
+                                                  &dtnode));
+
+    // by default, flags are all off
+    EXPECT_FALSE(dtnode->getFlag(TestDomainTreeNode::FLAG_CALLBACK));
+
+    // set operation, by default it enables the flag
+    dtnode->setFlag(TestDomainTreeNode::FLAG_CALLBACK);
+    EXPECT_TRUE(dtnode->getFlag(TestDomainTreeNode::FLAG_CALLBACK));
+
+    // try disable the flag explicitly
+    dtnode->setFlag(TestDomainTreeNode::FLAG_CALLBACK, false);
+    EXPECT_FALSE(dtnode->getFlag(TestDomainTreeNode::FLAG_CALLBACK));
+
+    // try enable the flag explicitly
+    dtnode->setFlag(TestDomainTreeNode::FLAG_CALLBACK, true);
+    EXPECT_TRUE(dtnode->getFlag(TestDomainTreeNode::FLAG_CALLBACK));
+
+    // setting an unknown flag will trigger an exception
+    EXPECT_THROW(dtnode->setFlag(static_cast<TestDomainTreeNode::Flags>(2), true),
+                 isc::InvalidParameter);
+}
+
+bool
+testCallback(const TestDomainTreeNode&, bool* callback_checker) {
+    *callback_checker = true;
+    return (false);
+}
+
+template <typename T>
+void
+performCallbackTest(TestDomainTree& dtree,
+                    util::MemorySegmentLocal& mem_sgmt,
+                    const T& name_called,
+                    const T& name_not_called)
+{
+    TestDomainTreeNode* dtnode;
+    const TestDomainTreeNode* cdtnode;
+
+    // by default callback isn't enabled
+    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt,
+                                                  Name("callback.example"),
+                                                  &dtnode));
+    EXPECT_EQ(static_cast<int*>(NULL), dtnode->setData(new int(1)));
+    EXPECT_FALSE(dtnode->getFlag(TestDomainTreeNode::FLAG_CALLBACK));
+
+    // enable/re-disable callback
+    dtnode->setFlag(TestDomainTreeNode::FLAG_CALLBACK);
+    EXPECT_TRUE(dtnode->getFlag(TestDomainTreeNode::FLAG_CALLBACK));
+    dtnode->setFlag(TestDomainTreeNode::FLAG_CALLBACK, false);
+    EXPECT_FALSE(dtnode->getFlag(TestDomainTreeNode::FLAG_CALLBACK));
+
+    // enable again for subsequent tests
+    dtnode->setFlag(TestDomainTreeNode::FLAG_CALLBACK);
+    // add more levels below and above the callback node for partial match.
+    TestDomainTreeNode* subdtnode;
+    EXPECT_EQ(TestDomainTree::SUCCESS, dtree.insert(mem_sgmt,
+                                                  Name("sub.callback.example"),
+                                                  &subdtnode));
+    EXPECT_EQ(static_cast<int*>(NULL), subdtnode->setData(new int(2)));
+    TestDomainTreeNode* parentdtnode;
+    EXPECT_EQ(TestDomainTree::ALREADYEXISTS, dtree.insert(mem_sgmt,
+                                                        Name("example"),
+                                                        &parentdtnode));
+    // the child/parent nodes shouldn't "inherit" the callback flag.
+    // "dtnode" may be invalid due to the insertion, so we need to re-find
+    // it.
+    EXPECT_EQ(TestDomainTree::EXACTMATCH, dtree.find(Name("callback.example"),
+                                                   &dtnode));
+    EXPECT_TRUE(dtnode->getFlag(TestDomainTreeNode::FLAG_CALLBACK));
+    EXPECT_FALSE(subdtnode->getFlag(TestDomainTreeNode::FLAG_CALLBACK));
+    EXPECT_FALSE(parentdtnode->getFlag(TestDomainTreeNode::FLAG_CALLBACK));
+
+    // check if the callback is called from find()
+    TestDomainTreeNodeChain node_path1;
+    bool callback_called = false;
+    EXPECT_EQ(TestDomainTree::EXACTMATCH,
+              dtree.find(name_called, &cdtnode, node_path1,
+                          testCallback, &callback_called));
+    EXPECT_TRUE(callback_called);
+
+    // enable callback at the parent node, but it doesn't have data so
+    // the callback shouldn't be called.
+    TestDomainTreeNodeChain node_path2;
+    parentdtnode->setFlag(TestDomainTreeNode::FLAG_CALLBACK);
+    callback_called = false;
+    EXPECT_EQ(TestDomainTree::EXACTMATCH,
+              dtree.find(name_not_called, &cdtnode, node_path2,
+                          testCallback, &callback_called));
+    EXPECT_FALSE(callback_called);
+}
+
+TEST_F(DomainTreeTest, callbackName) {
+    const Name n1("sub.callback.example");
+    const Name n2("callback.example");
+
+    performCallbackTest(dtree, mem_sgmt_, n1, n2);
+}
+
+TEST_F(DomainTreeTest, callbackLabelSequence) {
+    const Name n1("sub.callback.example");
+    const Name n2("callback.example");
+    const LabelSequence ls1(n1);
+    const LabelSequence ls2(n2);
+
+    performCallbackTest(dtree, mem_sgmt_, ls1, ls2);
+}
+
+TEST_F(DomainTreeTest, findInSubTree) {
+    // For the version that takes a node chain, the chain must be empty.
+    DomainTreeNodeChain<int> chain;
+    bool flag;
+
+    // Searching for a non-absolute (right-stripped) label sequence when
+    // chain is empty should throw.
+    const Name n0("w.y.d.e.f");
+    LabelSequence ls0(n0);
+    ls0.stripRight(1);
+    EXPECT_THROW(dtree_expose_empty_node.find(ls0, &cdtnode, chain,
+                                              testCallback, &flag),
+                 isc::BadValue);
+
+    // First, find a sub-tree node
+    chain.clear();
+    const LabelSequence ls1(n0);
+    DomainTree<int>::Result result =
+        dtree_expose_empty_node.find(ls1, &cdtnode, chain,
+                                     testCallback, &flag);
+    EXPECT_EQ(DomainTree<int>::EXACTMATCH, result);
+    EXPECT_EQ(n0, chain.getAbsoluteName());
+
+    // Searching for an absolute label sequence when chain is already
+    // populated should throw.
+    const Name n2a("o");
+    const LabelSequence ls2a(n2a);
+    EXPECT_THROW(dtree_expose_empty_node.find(ls2a, &cdtnode, chain,
+                                              testCallback, &flag),
+                 isc::BadValue);
+
+    // Now, find "o.w.y.d.e.f." by right-stripping the "w.y.d.e.f."
+    // suffix to "o" (non-absolute).
+    const Name n2("o.w.y.d.e.f");
+    LabelSequence ls2(n2);
+    ls2.stripRight(6);
+    EXPECT_EQ("o", ls2.toText());
+
+    result = dtree_expose_empty_node.find(ls2, &cdtnode, chain,
+                                          testCallback, &flag);
+    EXPECT_EQ(DomainTree<int>::EXACTMATCH, result);
+    EXPECT_EQ(n2, chain.getAbsoluteName());
+
+    // Another test. Start with "d.e.f." node.
+    chain.clear();
+    const Name n3("d.e.f");
+    const LabelSequence ls3(n3);
+    result =
+        dtree_expose_empty_node.find(ls3, &cdtnode, chain,
+                                     testCallback, &flag);
+    EXPECT_EQ(DomainTree<int>::EXACTMATCH, result);
+    EXPECT_EQ(n3, chain.getAbsoluteName());
+
+    // Now, find "o.w.y.d.e.f." by right-stripping the "w.y.d.e.f."
+    // suffix to "o.w.y" (non-absolute).
+    const Name n4("o.w.y.d.e.f");
+    LabelSequence ls4(n2);
+    ls4.stripRight(4);
+    EXPECT_EQ("o.w.y", ls4.toText());
+
+    result = dtree_expose_empty_node.find(ls4, &cdtnode, chain,
+                                          testCallback, &flag);
+    EXPECT_EQ(DomainTree<int>::EXACTMATCH, result);
+    EXPECT_EQ(n4, chain.getAbsoluteName());
+}
+
+TEST_F(DomainTreeTest, findInSubTreeSameLabelSequence) {
+    // For the version that takes a node chain, the chain must be empty.
+    DomainTreeNodeChain<int> chain;
+    bool flag;
+
+    const Name n1("c.g.h");
+
+    // First insert a "c.g.h." node.
+    dtree_expose_empty_node.insert(mem_sgmt_, n1, &dtnode);
+
+    /* Now, the tree looks like:
+     *
+     *             .
+     *             |
+     *             b
+     *           /   \
+     *          a    d.e.f
+     *              /  |  \____
+     *             c   |       \
+     *                 |        g.h
+     *                 |         |
+     *                w.y        i
+     *              /  |  \     / \
+     *             x   |   z   c   k
+     *                 |   |
+     *                 p   j
+     *               /   \
+     *              o     q
+     */
+
+    // Make a non-absolute label sequence. We will search for this same
+    // sequence in two places in the tree.
+    LabelSequence ls1(n1);
+    ls1.stripRight(3);
+    EXPECT_EQ("c", ls1.toText());
+
+    // First, find "g.h."
+    const Name n2("g.h");
+    const LabelSequence ls2(n2);
+    DomainTree<int>::Result result =
+        dtree_expose_empty_node.find(ls2, &cdtnode, chain,
+                                     testCallback, &flag);
+    EXPECT_EQ(DomainTree<int>::EXACTMATCH, result);
+    EXPECT_EQ(n2, chain.getAbsoluteName());
+
+    // Now, find "c.g.h." by searching just the non-absolute ls1 label
+    // sequence.
+    result = dtree_expose_empty_node.find(ls1, &cdtnode, chain,
+                                          testCallback, &flag);
+    EXPECT_EQ(DomainTree<int>::EXACTMATCH, result);
+    EXPECT_EQ(n1, chain.getAbsoluteName());
+
+    // Now, find "." (the root node)
+    chain.clear();
+    const Name n3(".");
+    const LabelSequence ls3(n3);
+    result =
+        dtree_expose_empty_node.find(ls3, &cdtnode, chain,
+                                     testCallback, &flag);
+    EXPECT_EQ(DomainTree<int>::EXACTMATCH, result);
+    EXPECT_EQ(n3, chain.getAbsoluteName());
+
+    // Now, find "c." by searching just the non-absolute ls1 label
+    // sequence.
+    result = dtree_expose_empty_node.find(ls1, &cdtnode, chain,
+                                          testCallback, &flag);
+    EXPECT_EQ(DomainTree<int>::EXACTMATCH, result);
+    EXPECT_EQ(Name("c."), chain.getAbsoluteName());
+}
+
+TEST_F(DomainTreeTest, chainLevel) {
+    TestDomainTreeNodeChain chain;
+
+    // by default there should be no level in the chain.
+    EXPECT_EQ(0, chain.getLevelCount());
+
+    // Copy should be consistent
+    TestDomainTreeNodeChain chain2(chain);
+    EXPECT_EQ(chain.getLevelCount(), chain2.getLevelCount());
+
+    // insert one node to the tree and find it.  there should be exactly
+    // one level in the chain.
+    TreeHolder tree_holder(mem_sgmt_, TestDomainTree::create(mem_sgmt_, true));
+    TestDomainTree& tree(*tree_holder.get());
+    Name node_name(Name::ROOT_NAME());
+    EXPECT_EQ(TestDomainTree::SUCCESS, tree.insert(mem_sgmt_, node_name,
+                                                &dtnode));
+    EXPECT_EQ(TestDomainTree::EXACTMATCH,
+              tree.find(node_name, &cdtnode, chain));
+    EXPECT_EQ(1, chain.getLevelCount());
+
+    // Copy should be consistent
+    TestDomainTreeNodeChain chain3(chain);
+    EXPECT_EQ(chain.getLevelCount(), chain3.getLevelCount());
+    EXPECT_EQ(chain.getAbsoluteName(), chain3.getAbsoluteName());
+
+    // Check the name of the found node (should have '.' as both non-absolute
+    // and absolute name
+    EXPECT_EQ(".", cdtnode->getLabels().toText());
+    EXPECT_EQ(".", cdtnode->getAbsoluteLabels(buf).toText());
+
+    /*
+     * Now creating a possibly deepest tree with MAX_LABELS levels.
+     * it should look like:
+     *           (.)
+     *            |
+     *            a
+     *            |
+     *            a
+     *            : (MAX_LABELS - 1) "a"'s
+     *
+     * then confirm that find() for the deepest name succeeds without any
+     * disruption, and the resulting chain has the expected level.
+     * Note that the root name (".") solely belongs to a single level,
+     * so the levels begin with 2.
+     */
+    for (unsigned int i = 2; i <= Name::MAX_LABELS; ++i) {
+        node_name = Name("a.").concatenate(node_name);
+        EXPECT_EQ(TestDomainTree::SUCCESS, tree.insert(mem_sgmt_, node_name,
+                                                    &dtnode));
+        TestDomainTreeNodeChain found_chain;
+        EXPECT_EQ(TestDomainTree::EXACTMATCH,
+                  tree.find(node_name, &cdtnode, found_chain));
+        EXPECT_EQ(i, found_chain.getLevelCount());
+
+        // The non-absolute name should only have the first label
+        EXPECT_EQ("a", cdtnode->getLabels().toText());
+        // But the absolute name should have all labels
+        EXPECT_EQ(node_name.toText(),
+                  cdtnode->getAbsoluteLabels(buf).toText());
+    }
+
+    // Confirm the last inserted name has the possible maximum length with
+    // maximum label count.  This confirms the dtree and chain level cannot
+    // be larger.
+    EXPECT_EQ(Name::MAX_LABELS, node_name.getLabelCount());
+    EXPECT_THROW(node_name.concatenate(Name("a.")), TooLongName);
+}
+
+TEST_F(DomainTreeTest, getAbsoluteNameError) {
+    // an empty chain isn't allowed.
+    TestDomainTreeNodeChain chain;
+    EXPECT_THROW(chain.getAbsoluteName(), BadValue);
+}
+
+/*
+ * The domain order should be:
+ * ., a, b, c, d.e.f, x.d.e.f, w.y.d.e.f, o.w.y.d.e.f, p.w.y.d.e.f,
+ * q.w.y.d.e.f, z.d.e.f, j.z.d.e.f, g.h, i.g.h, k.g.h
+ *             . (no data, can't be found)
+ *             |
+ *             b
+ *           /   \
+ *          a    d.e.f
+ *              /  |   \
+ *             c   |    g.h
+ *                 |     |
+ *                w.y    i
+ *              /  |  \   \
+ *             x   |   z   k
+ *                 |   |
+ *                 p   j
+ *               /   \
+ *              o     q
+ */
+const char* const names[] = {
+    "a", "b", "c", "d.e.f", "x.d.e.f", "w.y.d.e.f", "o.w.y.d.e.f",
+    "p.w.y.d.e.f", "q.w.y.d.e.f", "z.d.e.f", "j.z.d.e.f",
+    "g.h", "i.g.h", "k.g.h"};
+const size_t name_count(sizeof(names) / sizeof(*names));
+
+const char* const upper_node_names[] = {
+    ".", ".", ".", ".", "d.e.f", "d.e.f", "w.y.d.e.f",
+    "w.y.d.e.f", "w.y.d.e.f", "d.e.f", "z.d.e.f",
+    ".", "g.h", "g.h"};
+
+TEST_F(DomainTreeTest, getUpperNode) {
+    TestDomainTreeNodeChain node_path;
+    const TestDomainTreeNode* node = NULL;
+    EXPECT_EQ(TestDomainTree::EXACTMATCH,
+              dtree_expose_empty_node.find(Name(names[0]),
+                                            &node,
+                                            node_path));
+    for (int i = 0; i < name_count; ++i) {
+        EXPECT_NE(static_cast<void*>(NULL), node);
+
+        const TestDomainTreeNode* upper_node = node->getUpperNode();
+        if (upper_node_names[i] != NULL) {
+            const TestDomainTreeNode* upper_node2 = NULL;
+            EXPECT_EQ(TestDomainTree::EXACTMATCH,
+                      dtree_expose_empty_node.find(Name(upper_node_names[i]),
+                                                    &upper_node2));
+            EXPECT_NE(static_cast<void*>(NULL), upper_node2);
+            EXPECT_EQ(upper_node, upper_node2);
+        } else {
+            EXPECT_EQ(static_cast<void*>(NULL), upper_node);
+        }
+
+        node = dtree_expose_empty_node.nextNode(node_path);
+    }
+
+    // We should have reached the end of the tree.
+    EXPECT_EQ(static_cast<void*>(NULL), node);
+}
+
+
+#if 0
+// Disabled and kept still, for use in case we make getSubTreeRoot() a
+// public function again.
+
+const char* const subtree_root_node_names[] = {
+    "b", "b", "b", "b", "w.y.d.e.f", "w.y.d.e.f", "p.w.y.d.e.f",
+    "p.w.y.d.e.f", "p.w.y.d.e.f", "w.y.d.e.f", "j.z.d.e.f",
+    "b", "i.g.h", "i.g.h"};
+
+TEST_F(DomainTreeTest, getSubTreeRoot) {
+    TestDomainTreeNodeChain node_path;
+    const TestDomainTreeNode* node = NULL;
+    EXPECT_EQ(TestDomainTree::EXACTMATCH,
+              dtree_expose_empty_node.find(Name(names[0]),
+                                            &node,
+                                            node_path));
+    for (int i = 0; i < name_count; ++i) {
+        EXPECT_NE(static_cast<void*>(NULL), node);
+
+        const TestDomainTreeNode* sr_node = node->getSubTreeRoot();
+        if (subtree_root_node_names[i] != NULL) {
+            const TestDomainTreeNode* sr_node2 = NULL;
+            EXPECT_EQ(TestDomainTree::EXACTMATCH,
+                dtree_expose_empty_node.find(Name(subtree_root_node_names[i]),
+                                             &sr_node2));
+            EXPECT_NE(static_cast<void*>(NULL), sr_node2);
+            EXPECT_EQ(sr_node, sr_node2);
+        } else {
+            EXPECT_EQ(static_cast<void*>(NULL), sr_node);
+        }
+
+        node = dtree_expose_empty_node.nextNode(node_path);
+    }
+
+    // We should have reached the end of the tree.
+    EXPECT_EQ(static_cast<void*>(NULL), node);
+}
+
+#endif // disabled getSubTreeRoot()
+
+
+TEST_F(DomainTreeTest, nextNode) {
+    TestDomainTreeNodeChain node_path;
+    const TestDomainTreeNode* node = NULL;
+    EXPECT_EQ(TestDomainTree::EXACTMATCH,
+              dtree.find(Name(names[0]), &node, node_path));
+    for (int i = 0; i < name_count; ++i) {
+        EXPECT_NE(static_cast<void*>(NULL), node);
+        EXPECT_EQ(Name(names[i]), node_path.getAbsoluteName());
+        node = dtree.nextNode(node_path);
+    }
+
+    // We should have reached the end of the tree.
+    EXPECT_EQ(static_cast<void*>(NULL), node);
+}
+
+// Just walk using previousNode until the beginning of the tree and check it is
+// OK
+//
+// dtree - the tree to walk
+// node - result of previous call to find(), starting position of the walk
+// node_path - the path from the previous call to find(), will be modified
+// chain_length - the number of names that should be in the chain to be walked
+//   (0 means it should be empty, 3 means 'a', 'b' and 'c' should be there -
+//   this is always from the beginning of the names[] list).
+// skip_first - if this is false, the node should already contain the node with
+//   the first name of the chain. If it is true, the node should be NULL
+//   (true is for finds that return no match, false for the ones that return
+//   match)
+void
+previousWalk(TestDomainTree& dtree, const TestDomainTreeNode* node,
+             TestDomainTreeNodeChain& node_path, size_t chain_length,
+             bool skip_first)
+{
+    if (skip_first) {
+        // If the first is not found, this is supposed to be NULL and we skip
+        // it in our checks.
+        EXPECT_EQ(static_cast<void*>(NULL), node);
+        node = dtree.previousNode(node_path);
+    }
+    for (size_t i(chain_length); i > 0; --i) {
+        EXPECT_NE(static_cast<void*>(NULL), node);
+        EXPECT_EQ(Name(names[i - 1]), node_path.getAbsoluteName());
+        // Find the node at the path and check the value is the same
+        // (that it really returns the correct corresponding node)
+        //
+        // The "empty" nodes can not be found
+        if (node->getData()) {
+            const TestDomainTreeNode* node2(NULL);
+            TestDomainTreeNodeChain node_path2;
+            EXPECT_EQ(TestDomainTree::EXACTMATCH,
+                      dtree.find(Name(names[i - 1]), &node2, node_path2));
+            EXPECT_EQ(node, node2);
+        }
+        node = dtree.previousNode(node_path);
+    }
+
+    // We should have reached the start of the tree.
+    ASSERT_NE(static_cast<void*>(NULL), node);
+    EXPECT_EQ(".", node->getLabels().toText());
+
+    // With one more call it results in NULL
+    node = dtree.previousNode(node_path);
+    EXPECT_EQ(static_cast<void*>(NULL), node);
+
+    // Calling previousNode() yet again should still return NULL without
+    // fail.
+    node = dtree.previousNode(node_path);
+    EXPECT_EQ(static_cast<void*>(NULL), node);
+}
+
+// Check the previousNode
+TEST_F(DomainTreeTest, previousNode) {
+    // First, iterate the whole tree from the end to the beginning.
+    TestDomainTreeNodeChain node_path;
+    EXPECT_THROW(dtree.previousNode(node_path), isc::BadValue) <<
+        "Throw before a search was done on the path";
+    const TestDomainTreeNode* node(NULL);
+    {
+        SCOPED_TRACE("Iterate through");
+        EXPECT_EQ(TestDomainTree::EXACTMATCH,
+                  dtree.find(Name(names[name_count - 1]), &node, node_path));
+        previousWalk(dtree, node, node_path, name_count, false);
+        node = NULL;
+        node_path.clear();
+    }
+
+    {
+        SCOPED_TRACE("Iterate from the middle");
+        // Now, start somewhere in the middle, but within the real node.
+        EXPECT_EQ(TestDomainTree::EXACTMATCH,
+                  dtree.find(Name(names[4]), &node, node_path));
+        previousWalk(dtree, node, node_path, 5, false);
+        node = NULL;
+        node_path.clear();
+    }
+
+    {
+        SCOPED_TRACE("Start at the first");
+        // If we start at the lowest (which is "a"), we get to the beginning
+        // right away.
+        EXPECT_EQ(TestDomainTree::EXACTMATCH,
+                  dtree.find(Name(names[0]), &node, node_path));
+        EXPECT_NE(static_cast<void*>(NULL), node);
+        node = dtree.previousNode(node_path);
+        ASSERT_NE(static_cast<void*>(NULL), node);
+        EXPECT_EQ(".", node->getLabels().toText());
+        node = NULL;
+        node_path.clear();
+    }
+
+    {
+        SCOPED_TRACE("Start before the first");
+        // If we start before the lowest (. < 0. < a.), we should not get a
+        // node.  Its previous node should be the root.
+        EXPECT_EQ(TestDomainTree::NOTFOUND,
+                  dtree.find<void*>(Name("0"), &node, node_path, NULL, NULL));
+        EXPECT_EQ(static_cast<void*>(NULL), node);
+        node = dtree.previousNode(node_path);
+        ASSERT_NE(static_cast<void*>(NULL), node);
+        EXPECT_EQ(".", node->getLabels().toText());
+        node = NULL;
+        node_path.clear();
+    }
+
+    {
+        SCOPED_TRACE("Start after the last");
+        EXPECT_EQ(TestDomainTree::NOTFOUND,
+                  dtree.find(Name("z"), &node, node_path));
+        previousWalk(dtree, node, node_path, name_count, true);
+        node = NULL;
+        node_path.clear();
+    }
+
+    {
+        SCOPED_TRACE("Start below a leaf");
+        // We exit a leaf by going down. We should start by the one
+        // we exited - 'c' (actually, we should get it by the find, as partial
+        // match).
+        EXPECT_EQ(TestDomainTree::PARTIALMATCH,
+                  dtree.find(Name("b.c"), &node, node_path));
+        previousWalk(dtree, node, node_path, 3, false);
+        node = NULL;
+        node_path.clear();
+    }
+
+    {
+        SCOPED_TRACE("Start to the right of a leaf");
+        // When searching for this, we exit the 'x' node to the right side,
+        // so we should go x afterwards.
+
+        // The d.e.f is empty node, so it is hidden by find. Therefore NOTFOUND
+        // and not PARTIALMATCH.
+        EXPECT_EQ(TestDomainTree::NOTFOUND,
+                  dtree.find(Name("xy.d.e.f"), &node, node_path));
+        previousWalk(dtree, node, node_path, 5, true);
+        node = NULL;
+        node_path.clear();
+    }
+
+    {
+        SCOPED_TRACE("Start to the left of a leaf");
+        // This is similar to the previous, but we exit the 'z' leaf to the
+        // left side, so should not visit z at all then.
+
+        // The d.e.f is empty node, so it is hidden by find. Therefore NOTFOUND
+        // and not PARTIALMATCH.
+        EXPECT_EQ(TestDomainTree::NOTFOUND,
+                  dtree.find(Name("yz.d.e.f"), &node, node_path));
+        previousWalk(dtree, node, node_path, 9, true);
+        node = NULL;
+        node_path.clear();
+    }
+
+    {
+        SCOPED_TRACE("Start to the right of a parent");
+        // When searching for this, we exit the 'g.h' node to the right
+        // side, so we should go to g.h's children afterwards.
+
+        // 'g.h' is an empty node, so we get a NOTFOUND and not
+        // PARTIALMATCH.
+        EXPECT_EQ(TestDomainTree::NOTFOUND,
+                  dtree.find(Name("x.h"), &node, node_path));
+        // 'g.h' is the COMMONANCESTOR.
+        EXPECT_EQ(node_path.getLastComparedNode()->getName(), Name("g.h"));
+        EXPECT_EQ(NameComparisonResult::COMMONANCESTOR,
+                  node_path.getLastComparisonResult().getRelation());
+        // find() exits to the right of 'g.h'
+        EXPECT_GT(node_path.getLastComparisonResult().getOrder(), 0);
+        // We then descend into 'i.g.h' and walk all the nodes in the
+        // tree.
+        previousWalk(dtree, node, node_path, name_count, true);
+        node = NULL;
+        node_path.clear();
+    }
+
+    {
+        SCOPED_TRACE("Start inside a wrong node");
+        // The d.e.f is a single node, but we want only part of it. We
+        // should start iterating before it.
+        EXPECT_EQ(TestDomainTree::NOTFOUND,
+                  dtree.find(Name("e.f"), &node, node_path));
+        previousWalk(dtree, node, node_path, 3, true);
+        node = NULL;
+        node_path.clear();
+    }
+
+    {
+        SCOPED_TRACE("Lookup in empty tree");
+        // Just check it doesn't crash, etc.
+        TreeHolder tree_holder(mem_sgmt_, TestDomainTree::create(mem_sgmt_));
+        TestDomainTree& empty_tree(*tree_holder.get());
+        EXPECT_EQ(TestDomainTree::NOTFOUND,
+                  empty_tree.find(Name("x"), &node, node_path));
+        EXPECT_EQ(static_cast<void*>(NULL), node);
+        EXPECT_EQ(static_cast<void*>(NULL),
+                  empty_tree.previousNode(node_path));
+        node = NULL;
+        node_path.clear();
+    }
+}
+
+TEST_F(DomainTreeTest, largestNode) {
+    cdtnode = dtree.largestNode();
+    EXPECT_EQ(Name("k"), cdtnode->getName());
+
+    // Check for largest node in an empty tree.
+    TreeHolder empty_tree_holder
+        (mem_sgmt_, TestDomainTree::create(mem_sgmt_));
+    TestDomainTree& empty_tree(*empty_tree_holder.get());
+    EXPECT_EQ(static_cast<void*>(NULL), empty_tree.largestNode());
+}
+
+TEST_F(DomainTreeTest, nextNodeError) {
+    // Empty chain for nextNode() is invalid.
+    TestDomainTreeNodeChain chain;
+    EXPECT_THROW(dtree.nextNode(chain), BadValue);
+}
+
+// A helper function for getLastComparedNode() below.
+void
+comparisonChecks(const TestDomainTreeNodeChain& chain,
+                 int expected_order, int expected_common_labels,
+                 NameComparisonResult::NameRelation expected_reln)
+{
+    if (expected_order > 0) {
+        EXPECT_LT(0, chain.getLastComparisonResult().getOrder());
+    } else if (expected_order < 0) {
+        EXPECT_GT(0, chain.getLastComparisonResult().getOrder());
+    } else {
+        EXPECT_EQ(0, chain.getLastComparisonResult().getOrder());
+    }
+    EXPECT_EQ(expected_common_labels,
+              chain.getLastComparisonResult().getCommonLabels());
+    EXPECT_EQ(expected_reln,
+              chain.getLastComparisonResult().getRelation());
+}
+
+TEST_F(DomainTreeTest, getLastComparedNode) {
+    TestDomainTree& tree = dtree_expose_empty_node; // use the "empty OK" mode
+    TestDomainTreeNodeChain chain;
+
+    // initially there should be no 'last compared'.
+    EXPECT_EQ(static_cast<void*>(NULL), chain.getLastComparedNode());
+
+    // A search for an empty tree should result in no 'last compared', too.
+    TreeHolder tree_holder(mem_sgmt_, TestDomainTree::create(mem_sgmt_));
+    TestDomainTree& empty_tree(*tree_holder.get());
+    EXPECT_EQ(TestDomainTree::NOTFOUND,
+              empty_tree.find(Name("a"), &cdtnode, chain));
+    EXPECT_EQ(static_cast<void*>(NULL), chain.getLastComparedNode());
+    chain.clear();
+
+    const TestDomainTreeNode* expected_node = NULL;
+
+    // Exact match case.  The returned node should be last compared.
+    EXPECT_EQ(TestDomainTree::EXACTMATCH,
+              tree.find(Name("x.d.e.f"), &expected_node, chain));
+    EXPECT_EQ(expected_node, chain.getLastComparedNode());
+    // 1 = # labels of "x" (note: excluding ".")
+    comparisonChecks(chain, 0, 1, NameComparisonResult::EQUAL);
+    chain.clear();
+
+    // Partial match, search stopped at the matching node, which should be
+    // the last compared node.
+    EXPECT_EQ(TestDomainTree::EXACTMATCH,
+              tree.find(Name("k.g.h"), &expected_node));
+    EXPECT_EQ(TestDomainTree::PARTIALMATCH,
+              tree.find(Name("x.k.g.h"), &cdtnode, chain));
+    EXPECT_EQ(expected_node, chain.getLastComparedNode());
+    // k.g.h < x.k.g.h, 1 = # labels of "k"
+    comparisonChecks(chain, 1, 1, NameComparisonResult::SUBDOMAIN);
+    chain.clear();
+
+    // Partial match, search stopped in the subtree below the matching node
+    // after following a left branch.
+    EXPECT_EQ(TestDomainTree::EXACTMATCH,
+              tree.find(Name("x.d.e.f"), &expected_node));
+    EXPECT_EQ(TestDomainTree::PARTIALMATCH,
+              tree.find(Name("a.d.e.f"), &cdtnode, chain));
+    EXPECT_EQ(expected_node, chain.getLastComparedNode());
+    // a < x, no common labels
+    comparisonChecks(chain, -1, 0, NameComparisonResult::NONE);
+    chain.clear();
+
+    // Partial match, search stopped in the subtree below the matching node
+    // after following a right branch.
+    EXPECT_EQ(TestDomainTree::EXACTMATCH,
+              tree.find(Name("z.d.e.f"), &expected_node));
+    EXPECT_EQ(TestDomainTree::PARTIALMATCH,
+              tree.find(Name("zz.d.e.f"), &cdtnode, chain));
+    EXPECT_EQ(expected_node, chain.getLastComparedNode());
+    // zz > z, no common label
+    comparisonChecks(chain, 1, 0, NameComparisonResult::NONE);
+    chain.clear();
+
+    // Partial match, search stopped at a node for a super domain of the
+    // search name in the subtree below the matching node.
+    EXPECT_EQ(TestDomainTree::EXACTMATCH,
+              tree.find(Name("w.y.d.e.f"), &expected_node));
+    EXPECT_EQ(TestDomainTree::PARTIALMATCH,
+              tree.find(Name("y.d.e.f"), &cdtnode, chain));
+    EXPECT_EQ(expected_node, chain.getLastComparedNode());
+    // y < w.y, 1 = # labels of "y"
+    comparisonChecks(chain, -1, 1, NameComparisonResult::SUPERDOMAIN);
+    chain.clear();
+
+    // Partial match, search stopped at a node that share a common ancestor
+    // with the search name in the subtree below the matching node.
+    // (the expected node is the same as the previous case)
+    EXPECT_EQ(TestDomainTree::PARTIALMATCH,
+              tree.find(Name("z.y.d.e.f"), &cdtnode, chain));
+    EXPECT_EQ(expected_node, chain.getLastComparedNode());
+    // z.y > w.y, 1 = # labels of "y"
+    comparisonChecks(chain, 1, 1, NameComparisonResult::COMMONANCESTOR);
+    chain.clear();
+
+    // Search stops in the highest level (under ".") after following a left
+    // branch. (find() still returns PARTIALMATCH due to the top level ".")
+    EXPECT_EQ(TestDomainTree::EXACTMATCH, tree.find(Name("c"), &expected_node));
+    EXPECT_EQ(TestDomainTree::PARTIALMATCH,
+              tree.find(Name("bb"), &cdtnode, chain));
+    EXPECT_EQ(expected_node, chain.getLastComparedNode());
+    // bb < c, no common label
+    comparisonChecks(chain, -1, 0, NameComparisonResult::NONE);
+    chain.clear();
+
+    // Search stops in the highest level (under ".") after following a right
+    // branch. (the expected node is the same as the previous case)
+    EXPECT_EQ(TestDomainTree::PARTIALMATCH,
+              tree.find(Name("d"), &cdtnode, chain));
+    EXPECT_EQ(expected_node, chain.getLastComparedNode());
+    // d > c, no common label
+    comparisonChecks(chain, 1, 0, NameComparisonResult::NONE);
+    chain.clear();
+}
+
+TEST_F(DomainTreeTest, dumpTree) {
+    std::ostringstream str;
+    std::ostringstream str2;
+    dtree.dumpTree(str);
+    str2 << "tree has 15 node(s)\n"
+            ". (black) [invisible] [subtreeroot]\n"
+            "     begin down from .\n"
+            "     b (black) [subtreeroot]\n"
+            "          a (black)\n"
+            "               NULL\n"
+            "               NULL\n"
+            "          d.e.f (black) [invisible]\n"
+            "               begin down from d.e.f\n"
+            "               w.y (black) [invisible] [subtreeroot]\n"
+            "                    begin down from w.y\n"
+            "                    p (black) [subtreeroot]\n"
+            "                         o (red)\n"
+            "                              NULL\n"
+            "                              NULL\n"
+            "                         q (red)\n"
+            "                              NULL\n"
+            "                              NULL\n"
+            "                    end down from w.y\n"
+            "                    x (red)\n"
+            "                         NULL\n"
+            "                         NULL\n"
+            "                    z (red)\n"
+            "                         begin down from z\n"
+            "                         j (black) [subtreeroot]\n"
+            "                              NULL\n"
+            "                              NULL\n"
+            "                         end down from z\n"
+            "                         NULL\n"
+            "                         NULL\n"
+            "               end down from d.e.f\n"
+            "               c (red)\n"
+            "                    NULL\n"
+            "                    NULL\n"
+            "               g.h (red)\n"
+            "                    begin down from g.h\n"
+            "                    i (black) [subtreeroot]\n"
+            "                         NULL\n"
+            "                         k (red)\n"
+            "                              NULL\n"
+            "                              NULL\n"
+            "                    end down from g.h\n"
+            "                    NULL\n"
+            "                    NULL\n"
+            "     end down from .\n"
+            "     NULL\n"
+            "     NULL\n";
+    EXPECT_EQ(str2.str(), str.str());
+}
+
+TEST_F(DomainTreeTest, swap) {
+    // Store info about the first tree
+    std::ostringstream str1;
+    dtree.dumpTree(str1);
+    size_t count1(dtree.getNodeCount());
+
+    // Create second one and store state
+    TreeHolder tree_holder(mem_sgmt_, TestDomainTree::create(mem_sgmt_));
+    TestDomainTree& tree2(*tree_holder.get());
+    TestDomainTreeNode* node;
+    tree2.insert(mem_sgmt_, Name("second"), &node);
+    std::ostringstream str2;
+    tree2.dumpTree(str2);
+
+    // Swap them
+    ASSERT_NO_THROW(tree2.swap(dtree));
+
+    // Check their sizes
+    ASSERT_EQ(1, dtree.getNodeCount());
+    ASSERT_EQ(count1, tree2.getNodeCount());
+
+    // And content
+    std::ostringstream out;
+    dtree.dumpTree(out);
+    ASSERT_EQ(str2.str(), out.str());
+    out.str("");
+    tree2.dumpTree(out);
+    ASSERT_EQ(str1.str(), out.str());
+}
+
+// Matching in the "root zone" may be special (e.g. there's no parent,
+// any domain names should be considered a subdomain of it), so it makes
+// sense to test cases with the root zone explicitly.
+TEST_F(DomainTreeTest, root) {
+    TreeHolder tree_holder(mem_sgmt_, TestDomainTree::create(mem_sgmt_));
+    TestDomainTree& root(*tree_holder.get());
+    root.insert(mem_sgmt_, Name::ROOT_NAME(), &dtnode);
+    EXPECT_EQ(static_cast<int*>(NULL), dtnode->setData(new int(1)));
+
+    EXPECT_EQ(TestDomainTree::EXACTMATCH,
+              root.find(Name::ROOT_NAME(), &cdtnode));
+    EXPECT_EQ(dtnode, cdtnode);
+    EXPECT_EQ(TestDomainTree::PARTIALMATCH,
+              root.find(Name("example.com"), &cdtnode));
+    EXPECT_EQ(dtnode, cdtnode);
+
+    // Insert a new name that better matches the query name.  find() should
+    // find the better one.
+    root.insert(mem_sgmt_, Name("com"), &dtnode);
+    EXPECT_EQ(static_cast<int*>(NULL), dtnode->setData(new int(2)));
+    EXPECT_EQ(TestDomainTree::PARTIALMATCH,
+              root.find(Name("example.com"), &cdtnode));
+    EXPECT_EQ(dtnode, cdtnode);
+
+    // Perform the same tests for the tree that allows matching against empty
+    // nodes.
+    TreeHolder tree_holder_emptyok(mem_sgmt_,
+                                   TestDomainTree::create(mem_sgmt_, true));
+    TestDomainTree& root_emptyok(*tree_holder_emptyok.get());
+    root_emptyok.insert(mem_sgmt_, Name::ROOT_NAME(), &dtnode);
+    EXPECT_EQ(TestDomainTree::EXACTMATCH,
+              root_emptyok.find(Name::ROOT_NAME(), &cdtnode));
+    EXPECT_EQ(dtnode, cdtnode);
+    EXPECT_EQ(TestDomainTree::PARTIALMATCH,
+              root_emptyok.find(Name("example.com"), &cdtnode));
+    EXPECT_EQ(dtnode, cdtnode);
+
+    root.insert(mem_sgmt_, Name("com"), &dtnode);
+    EXPECT_EQ(TestDomainTree::PARTIALMATCH,
+              root.find(Name("example.com"), &cdtnode));
+    EXPECT_EQ(dtnode, cdtnode);
+}
+
+TEST_F(DomainTreeTest, getAbsoluteLabels) {
+    // The full absolute names of the nodes in the tree
+    // with the addition of the explicit root node
+    const char* const domain_names[] = {
+        "c", "b", "a", "x.d.e.f", "z.d.e.f", "g.h", "i.g.h", "o.w.y.d.e.f",
+        "j.z.d.e.f", "p.w.y.d.e.f", "q.w.y.d.e.f", "k.g.h"};
+    // The names of the nodes themselves, as they end up in the tree
+    const char* const first_labels[] = {
+        "c", "b", "a", "x", "z", "g.h", "i", "o",
+        "j", "p", "q", "k"};
+
+    const int name_count = sizeof(domain_names) / sizeof(domain_names[0]);
+    for (int i = 0; i < name_count; ++i) {
+        EXPECT_EQ(TestDomainTree::EXACTMATCH, dtree.find(Name(domain_names[i]),
+                  &cdtnode));
+
+        // First make sure the names themselves are not absolute
+        const LabelSequence ls(cdtnode->getLabels());
+        EXPECT_EQ(first_labels[i], ls.toText());
+        EXPECT_FALSE(ls.isAbsolute());
+
+        // Now check the absolute names
+        const LabelSequence abs_ls(cdtnode->getAbsoluteLabels(buf));
+        EXPECT_EQ(Name(domain_names[i]).toText(), abs_ls.toText());
+        EXPECT_TRUE(abs_ls.isAbsolute());
+    }
+
+    // Explicitly add and find a root node, to see that getAbsoluteLabels
+    // also works when getLabels() already returns an absolute LabelSequence
+    dtree.insert(mem_sgmt_, Name("."), &dtnode);
+    dtnode->setData(new int(1));
+
+    EXPECT_EQ(TestDomainTree::EXACTMATCH, dtree.find(Name("."), &cdtnode));
+
+    EXPECT_TRUE(cdtnode->getLabels().isAbsolute());
+    EXPECT_EQ(".", cdtnode->getLabels().toText());
+    EXPECT_TRUE(cdtnode->getAbsoluteLabels(buf).isAbsolute());
+    EXPECT_EQ(".", cdtnode->getAbsoluteLabels(buf).toText());
+}
+}
diff --git a/src/lib/datasrc/tests/memory/memory_client_unittest.cc b/src/lib/datasrc/tests/memory/memory_client_unittest.cc
new file mode 100644
index 0000000..58979a4
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/memory_client_unittest.cc
@@ -0,0 +1,777 @@
+// 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 <exceptions/exceptions.h>
+
+#include <util/memory_segment_local.h>
+
+#include <dns/name.h>
+#include <dns/rrclass.h>
+#include <dns/masterload.h>
+#include <dns/nsec3hash.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rrsetlist.h>
+#include <dns/rrttl.h>
+#include <dns/masterload.h>
+
+#include <datasrc/result.h>
+#include <datasrc/data_source.h>
+#include <datasrc/memory/zone_data.h>
+#include <datasrc/memory/zone_table.h>
+#include <datasrc/memory/memory_client.h>
+
+#include <testutils/dnsmessage_test.h>
+
+#include "memory_segment_test.h"
+
+#include <gtest/gtest.h>
+
+#include <new>                  // for bad_alloc
+
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+using namespace isc::datasrc;
+using namespace isc::datasrc::memory;
+using namespace isc::testutils;
+
+namespace {
+
+const char* rrset_data[] = {
+    "example.org. 3600 IN SOA ns1.example.org. bugs.x.w.example.org. "
+    "68 3600 300 3600000 3600",
+    "a.example.org. 3600 IN A 192.168.0.1\n" // RRset containing 2 RRs
+    "a.example.org. 3600 IN A 192.168.0.2",
+    "a.example.org. 3600 IN RRSIG A 5 3 3600 20150420235959 20051021000000 "
+    "40430 example.org. FAKEFAKE",
+    "a.example.org. 3600 IN MX 10 mail.example.org.",
+    "a.example.org. 3600 IN RRSIG MX 5 3 3600 20150420235959 20051021000000 "
+    "40430 example.org. FAKEFAKEFAKE",
+    NULL
+};
+
+// RRsets that emulate the "separate RRs" mode.
+const char* rrset_data_separated[] = {
+    "example.org. 3600 IN SOA ns1.example.org. bugs.x.w.example.org. "
+    "68 3600 300 3600000 3600",
+    "a.example.org. 3600 IN A 192.168.0.1", // these two belong to the same
+    "a.example.org. 3600 IN A 192.168.0.2", // RRset, but are separated.
+    NULL
+};
+
+// Similar to the previous one, but with separated RRSIGs
+const char* rrset_data_sigseparated[] = {
+    "example.org. 3600 IN SOA ns1.example.org. bugs.x.w.example.org. "
+    "68 3600 300 3600000 3600",
+    "a.example.org. 3600 IN A 192.168.0.1",
+    "a.example.org. 3600 IN RRSIG A 5 3 3600 20150420235959 20051021000000 "
+    "40430 example.org. FAKEFAKE",
+    "a.example.org. 3600 IN RRSIG A 5 3 3600 20150420235959 20051021000000 "
+    "53535 example.org. FAKEFAKE",
+    NULL
+};
+
+class MockIterator : public ZoneIterator {
+private:
+    MockIterator(const char** rrset_data_ptr, bool pass_empty_rrsig) :
+        rrset_data_ptr_(rrset_data_ptr),
+        pass_empty_rrsig_(pass_empty_rrsig)
+    {
+    }
+
+    const char** rrset_data_ptr_;
+    // If true, emulate an unexpected bogus case where an RRSIG RRset is
+    // returned without the RDATA.  For brevity allow tests tweak it directly.
+    bool pass_empty_rrsig_;
+
+public:
+    virtual ConstRRsetPtr getNextRRset() {
+        if (*rrset_data_ptr_ == NULL) {
+             return (ConstRRsetPtr());
+        }
+
+        ConstRRsetPtr result(textToRRset(*rrset_data_ptr_,
+                                         RRClass::IN(), Name("example.org")));
+        if (pass_empty_rrsig_ && result->getType() == RRType::RRSIG()) {
+            result.reset(new RRset(result->getName(), result->getClass(),
+                                   result->getType(), result->getTTL()));
+        }
+        ++rrset_data_ptr_;
+
+        return (result);
+    }
+
+    virtual ConstRRsetPtr getSOA() const {
+        isc_throw(isc::NotImplemented, "Not implemented");
+    }
+
+    static ZoneIteratorPtr makeIterator(const char** rrset_data_ptr,
+                                        bool pass_empty_rrsig = false)
+    {
+        return (ZoneIteratorPtr(new MockIterator(rrset_data_ptr,
+                                                 pass_empty_rrsig)));
+    }
+};
+
+class MemoryClientTest : public ::testing::Test {
+protected:
+    MemoryClientTest() : zclass_(RRClass::IN()),
+                         client_(new InMemoryClient(mem_sgmt_, zclass_))
+    {}
+    ~MemoryClientTest() {
+        if (client_ != NULL) {
+            delete client_;
+        }
+    }
+    void TearDown() {
+        delete client_;
+        client_ = NULL;
+        EXPECT_TRUE(mem_sgmt_.allMemoryDeallocated()); // catch any leak here.
+    }
+    const RRClass zclass_;
+    test::MemorySegmentTest mem_sgmt_;
+    InMemoryClient* client_;
+};
+
+TEST_F(MemoryClientTest, loadRRsetDoesntMatchOrigin) {
+    // Attempting to load example.org to example.com zone should result
+    // in an exception.
+    EXPECT_THROW(client_->load(Name("example.com"),
+                               TEST_DATA_DIR "/example.org-empty.zone"),
+                 MasterLoadError);
+}
+
+TEST_F(MemoryClientTest, loadErrorsInParsingZoneMustNotLeak1) {
+    // Attempting to load broken example.org zone should result in an
+    // exception. This should not leak ZoneData and other such
+    // allocations.
+    EXPECT_THROW(client_->load(Name("example.org"),
+                               TEST_DATA_DIR "/example.org-broken1.zone"),
+                 MasterLoadError);
+    // Teardown checks for memory segment leaks
+}
+
+TEST_F(MemoryClientTest, loadErrorsInParsingZoneMustNotLeak2) {
+    // Attempting to load broken example.org zone should result in an
+    // exception. This should not leak ZoneData and other such
+    // allocations.
+    EXPECT_THROW(client_->load(Name("example.org"),
+                               TEST_DATA_DIR "/example.org-broken2.zone"),
+                 MasterLoadError);
+    // Teardown checks for memory segment leaks
+}
+
+TEST_F(MemoryClientTest, loadNonExistentZoneFile) {
+    EXPECT_THROW(client_->load(Name("example.org"),
+                               TEST_DATA_DIR "/somerandomfilename"),
+                 MasterLoadError);
+    // Teardown checks for memory segment leaks
+}
+
+TEST_F(MemoryClientTest, loadEmptyZoneFileThrows) {
+    // When an empty zone file is loaded, the origin doesn't even have
+    // an SOA RR. This condition should be avoided, and hence load()
+    // should throw when an empty zone is loaded.
+
+    EXPECT_EQ(0, client_->getZoneCount());
+
+    EXPECT_THROW(client_->load(Name("."),
+                               TEST_DATA_DIR "/empty.zone"),
+                 InMemoryClient::EmptyZone);
+
+    EXPECT_EQ(0, client_->getZoneCount());
+
+    // Teardown checks for memory segment leaks
+}
+
+TEST_F(MemoryClientTest, load) {
+    // This is a simple load check for a "full" and correct zone that
+    // should not result in any exceptions.
+    client_->load(Name("example.org"),
+                  TEST_DATA_DIR "/example.org.zone");
+    const ZoneData* zone_data =
+        client_->findZoneData(Name("example.org"));
+    ASSERT_NE(static_cast<const ZoneData*>(NULL), zone_data);
+    EXPECT_FALSE(zone_data->isSigned());
+    EXPECT_FALSE(zone_data->isNSEC3Signed());
+}
+
+TEST_F(MemoryClientTest, loadFromIterator) {
+    client_->load(Name("example.org"),
+                  *MockIterator::makeIterator(rrset_data));
+
+    ZoneIteratorPtr iterator(client_->getIterator(Name("example.org")));
+
+    // First we have the SOA
+    ConstRRsetPtr rrset(iterator->getNextRRset());
+    EXPECT_TRUE(rrset);
+    EXPECT_EQ(RRType::SOA(), rrset->getType());
+
+    // RRType::MX() RRset
+    rrset = iterator->getNextRRset();
+    EXPECT_TRUE(rrset);
+    EXPECT_EQ(RRType::MX(), rrset->getType());
+    EXPECT_EQ(1, rrset->getRRsigDataCount()); // this RRset is signed
+
+    // RRType::A() RRset
+    rrset = iterator->getNextRRset();
+    EXPECT_TRUE(rrset);
+    EXPECT_EQ(RRType::A(), rrset->getType());
+    EXPECT_EQ(1, rrset->getRRsigDataCount()); // also signed
+
+    // There's nothing else in this iterator
+    EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
+
+    // Iterating past the end should result in an exception
+    EXPECT_THROW(iterator->getNextRRset(), isc::Unexpected);
+
+    // Loading the zone with an iterator separating RRs of the same RRset
+    // will fail because the resulting sequence doesn't meet assumptions of
+    // the (current) in-memory implementation.
+    EXPECT_THROW(client_->load(Name("example.org"),
+                               *MockIterator::makeIterator(
+                                   rrset_data_separated)),
+                 InMemoryClient::AddError);
+
+    // Similar to the previous case, but with separated RRSIGs.
+    EXPECT_THROW(client_->load(Name("example.org"),
+                               *MockIterator::makeIterator(
+                                   rrset_data_sigseparated)),
+                 InMemoryClient::AddError);
+
+    // Emulating bogus iterator implementation that passes empty RRSIGs.
+    EXPECT_THROW(client_->load(Name("example.org"),
+                               *MockIterator::makeIterator(rrset_data, true)),
+                 isc::Unexpected);
+}
+
+TEST_F(MemoryClientTest, loadMemoryAllocationFailures) {
+    // Just to check that things get cleaned up
+
+    for (int i = 1; i < 16; i++) {
+        mem_sgmt_.setThrowCount(i);
+        EXPECT_THROW(client_->load(Name("example.org"),
+                                   TEST_DATA_DIR "/example.org.zone"),
+                     std::bad_alloc);
+    }
+    // Teardown checks for memory segment leaks
+}
+
+TEST_F(MemoryClientTest, loadNSEC3Signed) {
+    client_->load(Name("example.org"),
+                  TEST_DATA_DIR "/example.org-nsec3-signed.zone");
+    const ZoneData* zone_data =
+        client_->findZoneData(Name("example.org"));
+    ASSERT_NE(static_cast<const ZoneData*>(NULL), zone_data);
+    EXPECT_TRUE(zone_data->isSigned());
+    EXPECT_TRUE(zone_data->isNSEC3Signed());
+}
+
+TEST_F(MemoryClientTest, loadNSEC3EmptySalt) {
+    // Load NSEC3 with empty ("-") salt. This should not throw or crash
+    // or anything.
+    client_->load(Name("example.org"),
+                  TEST_DATA_DIR "/example.org-nsec3-empty-salt.zone");
+    const ZoneData* zone_data =
+        client_->findZoneData(Name("example.org"));
+    ASSERT_NE(static_cast<const ZoneData*>(NULL), zone_data);
+    EXPECT_TRUE(zone_data->isSigned());
+    EXPECT_TRUE(zone_data->isNSEC3Signed());
+}
+
+TEST_F(MemoryClientTest, loadNSEC3SignedNoParam) {
+    client_->load(Name("example.org"),
+                  TEST_DATA_DIR "/example.org-nsec3-signed-no-param.zone");
+    const ZoneData* zone_data =
+        client_->findZoneData(Name("example.org"));
+    ASSERT_NE(static_cast<const ZoneData*>(NULL), zone_data);
+    EXPECT_TRUE(zone_data->isSigned());
+    EXPECT_TRUE(zone_data->isNSEC3Signed());
+}
+
+TEST_F(MemoryClientTest, loadReloadZone) {
+    // Because we reload the same zone, also check that the zone count
+    // doesn't increase.
+    EXPECT_EQ(0, client_->getZoneCount());
+
+    client_->load(Name("example.org"),
+                  TEST_DATA_DIR "/example.org-empty.zone");
+    EXPECT_EQ(1, client_->getZoneCount());
+
+    // Reload zone with same data
+
+    client_->load(Name("example.org"),
+                  client_->getFileName(Name("example.org")));
+    EXPECT_EQ(1, client_->getZoneCount());
+
+    const ZoneData* zone_data =
+        client_->findZoneData(Name("example.org"));
+    EXPECT_NE(static_cast<const ZoneData*>(NULL), zone_data);
+
+    /* Check SOA */
+    const ZoneNode* node = zone_data->getOriginNode();
+    EXPECT_NE(static_cast<const ZoneNode*>(NULL), node);
+
+    const RdataSet* set = node->getData();
+    EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
+    EXPECT_EQ(RRType::SOA(), set->type);
+
+    set = set->getNext();
+    EXPECT_EQ(static_cast<const RdataSet*>(NULL), set);
+
+    /* Check ns1.example.org */
+    const ZoneTree& tree = zone_data->getZoneTree();
+    ZoneTree::Result zresult(tree.find(Name("ns1.example.org"), &node));
+    EXPECT_NE(ZoneTree::EXACTMATCH, zresult);
+
+    // Reload zone with different data
+
+    client_->load(Name("example.org"),
+                  TEST_DATA_DIR "/example.org-rrsigs.zone");
+    EXPECT_EQ(1, client_->getZoneCount());
+
+    zone_data = client_->findZoneData(Name("example.org"));
+    EXPECT_NE(static_cast<const ZoneData*>(NULL), zone_data);
+
+    /* Check SOA */
+    node = zone_data->getOriginNode();
+    EXPECT_NE(static_cast<const ZoneNode*>(NULL), node);
+
+    set = node->getData();
+    EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
+    EXPECT_EQ(RRType::SOA(), set->type);
+
+    set = set->getNext();
+    EXPECT_EQ(static_cast<const RdataSet*>(NULL), set);
+
+    /* Check ns1.example.org */
+    const ZoneTree& tree2 = zone_data->getZoneTree();
+    ZoneTree::Result zresult2(tree2.find(Name("ns1.example.org"), &node));
+    EXPECT_EQ(ZoneTree::EXACTMATCH, zresult2);
+    EXPECT_NE(static_cast<const ZoneNode*>(NULL), node);
+
+    set = node->getData();
+    EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
+    EXPECT_EQ(RRType::AAAA(), set->type);
+
+    set = set->getNext();
+    EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
+    EXPECT_EQ(RRType::A(), set->type);
+
+    set = set->getNext();
+    EXPECT_EQ(static_cast<const RdataSet*>(NULL), set);
+
+    // Teardown checks for memory segment leaks
+}
+
+TEST_F(MemoryClientTest, loadDuplicateType) {
+    // This should not result in any exceptions:
+    client_->load(Name("example.org"),
+                  TEST_DATA_DIR "/example.org-duplicate-type.zone");
+
+    // This should throw:
+    EXPECT_THROW(client_->load(Name("example.org"),
+                               TEST_DATA_DIR
+                               "/example.org-duplicate-type-bad.zone"),
+                 InMemoryClient::AddError);
+    // Teardown checks for memory segment leaks
+}
+
+TEST_F(MemoryClientTest, loadMultipleCNAMEThrows) {
+    // Multiple CNAME RRs should throw.
+    EXPECT_THROW(client_->load(Name("example.org"),
+                               TEST_DATA_DIR
+                               "/example.org-multiple-cname.zone"),
+                 InMemoryClient::AddError);
+    // Teardown checks for memory segment leaks
+}
+
+TEST_F(MemoryClientTest, loadMultipleDNAMEThrows) {
+    // Multiple DNAME RRs should throw.
+    EXPECT_THROW(client_->load(Name("example.org"),
+                               TEST_DATA_DIR
+                               "/example.org-multiple-dname.zone"),
+                 InMemoryClient::AddError);
+    // Teardown checks for memory segment leaks
+}
+
+TEST_F(MemoryClientTest, loadMultipleNSEC3Throws) {
+    // Multiple NSEC3 RRs should throw.
+    EXPECT_THROW(client_->load(Name("example.org"),
+                               TEST_DATA_DIR
+                               "/example.org-multiple-nsec3.zone"),
+                 InMemoryClient::AddError);
+    // Teardown checks for memory segment leaks
+}
+
+TEST_F(MemoryClientTest, loadMultipleNSEC3PARAMThrows) {
+    // Multiple NSEC3PARAM RRs should throw.
+    EXPECT_THROW(client_->load(Name("example.org"),
+                               TEST_DATA_DIR
+                               "/example.org-multiple-nsec3param.zone"),
+                 InMemoryClient::AddError);
+    // Teardown checks for memory segment leaks
+}
+
+TEST_F(MemoryClientTest, loadOutOfZoneThrows) {
+    // Out of zone names should throw.
+    EXPECT_THROW(client_->load(Name("example.org"),
+                               TEST_DATA_DIR
+                               "/example.org-out-of-zone.zone"),
+                 MasterLoadError);
+    // Teardown checks for memory segment leaks
+}
+
+TEST_F(MemoryClientTest, loadWildcardNSThrows) {
+    // Wildcard NS names should throw
+    EXPECT_THROW(client_->load(Name("example.org"),
+                               TEST_DATA_DIR
+                               "/example.org-wildcard-ns.zone"),
+                 InMemoryClient::AddError);
+    // Teardown checks for memory segment leaks
+}
+
+TEST_F(MemoryClientTest, loadWildcardDNAMEThrows) {
+    // Wildcard DNAME names should throw
+    EXPECT_THROW(client_->load(Name("example.org"),
+                               TEST_DATA_DIR
+                               "/example.org-wildcard-dname.zone"),
+                 InMemoryClient::AddError);
+    // Teardown checks for memory segment leaks
+}
+
+TEST_F(MemoryClientTest, loadWildcardNSEC3Throws) {
+    // Wildcard NSEC3 names should throw
+    EXPECT_THROW(client_->load(Name("example.org"),
+                               TEST_DATA_DIR
+                               "/example.org-wildcard-nsec3.zone"),
+                 InMemoryClient::AddError);
+    // Teardown checks for memory segment leaks
+}
+
+TEST_F(MemoryClientTest, loadNSEC3WithFewerLabelsThrows) {
+    // NSEC3 names with labels != (origin_labels + 1) should throw
+    EXPECT_THROW(client_->load(Name("example.org"),
+                               TEST_DATA_DIR
+                               "/example.org-nsec3-fewer-labels.zone"),
+                 InMemoryClient::AddError);
+    // Teardown checks for memory segment leaks
+}
+
+TEST_F(MemoryClientTest, loadNSEC3WithMoreLabelsThrows) {
+    // NSEC3 names with labels != (origin_labels + 1) should throw
+    EXPECT_THROW(client_->load(Name("example.org"),
+                               TEST_DATA_DIR
+                               "/example.org-nsec3-more-labels.zone"),
+                 InMemoryClient::AddError);
+    // Teardown checks for memory segment leaks
+}
+
+TEST_F(MemoryClientTest, loadCNAMEAndNotNSECThrows) {
+    // CNAME and not NSEC should throw
+    EXPECT_THROW(client_->load(Name("example.org"),
+                               TEST_DATA_DIR
+                               "/example.org-cname-and-not-nsec-1.zone"),
+                 InMemoryClient::AddError);
+
+    EXPECT_THROW(client_->load(Name("example.org"),
+                               TEST_DATA_DIR
+                               "/example.org-cname-and-not-nsec-2.zone"),
+                 InMemoryClient::AddError);
+
+    // Teardown checks for memory segment leaks
+}
+
+TEST_F(MemoryClientTest, loadDNAMEAndNSApex1) {
+    // DNAME + NS (apex) is OK
+    client_->load(Name("example.org"),
+                  TEST_DATA_DIR
+                  "/example.org-dname-ns-apex-1.zone");
+    // Teardown checks for memory segment leaks
+}
+
+TEST_F(MemoryClientTest, loadDNAMEAndNSApex2) {
+    // DNAME + NS (apex) is OK (reverse order)
+    client_->load(Name("example.org"),
+                  TEST_DATA_DIR
+                  "/example.org-dname-ns-apex-2.zone");
+    // Teardown checks for memory segment leaks
+}
+
+TEST_F(MemoryClientTest, loadDNAMEAndNSNonApex1) {
+    // DNAME + NS (non-apex) must throw
+    EXPECT_THROW(client_->load(Name("example.org"),
+                               TEST_DATA_DIR
+                               "/example.org-dname-ns-nonapex-1.zone"),
+                 InMemoryClient::AddError);
+    // Teardown checks for memory segment leaks
+}
+
+TEST_F(MemoryClientTest, loadDNAMEAndNSNonApex2) {
+    // DNAME + NS (non-apex) must throw (reverse order)
+    EXPECT_THROW(client_->load(Name("example.org"),
+                               TEST_DATA_DIR
+                               "/example.org-dname-ns-nonapex-2.zone"),
+                 InMemoryClient::AddError);
+    // Teardown checks for memory segment leaks
+}
+
+TEST_F(MemoryClientTest, loadRRSIGFollowsNothing) {
+    // This causes the situation where an RRSIG is added without a covered
+    // RRset.  Such cases are currently rejected.
+    EXPECT_THROW(client_->load(Name("example.org"),
+                               TEST_DATA_DIR
+                               "/example.org-rrsig-follows-nothing.zone"),
+                 InMemoryClient::AddError);
+    // Teardown checks for memory segment leaks
+}
+
+TEST_F(MemoryClientTest, loadRRSIGs) {
+    client_->load(Name("example.org"),
+                  TEST_DATA_DIR "/example.org-rrsigs.zone");
+    EXPECT_EQ(1, client_->getZoneCount());
+}
+
+TEST_F(MemoryClientTest, loadRRSIGsRdataMixedCoveredTypes) {
+    client_->load(Name("example.org"),
+                  TEST_DATA_DIR "/example.org-rrsigs.zone");
+
+    RRsetPtr rrset(new RRset(Name("example.org"),
+                             RRClass::IN(), RRType::A(), RRTTL(3600)));
+    rrset->addRdata(in::A("192.0.2.1"));
+    rrset->addRdata(in::A("192.0.2.2"));
+
+    RRsetPtr rrsig(new RRset(Name("example.org"), zclass_,
+                             RRType::RRSIG(), RRTTL(300)));
+    rrsig->addRdata(generic::RRSIG("A 5 3 3600 20000101000000 20000201000000 "
+                                   "12345 example.org. FAKEFAKEFAKE"));
+    rrsig->addRdata(generic::RRSIG("NS 5 3 3600 20000101000000 20000201000000 "
+                                   "54321 example.org. FAKEFAKEFAKEFAKE"));
+    rrset->addRRsig(rrsig);
+
+    EXPECT_THROW(client_->add(Name("example.org"), rrset),
+                 InMemoryClient::AddError);
+
+    // Teardown checks for memory segment leaks
+}
+
+TEST_F(MemoryClientTest, getZoneCount) {
+    EXPECT_EQ(0, client_->getZoneCount());
+    client_->load(Name("example.org"), TEST_DATA_DIR "/example.org-empty.zone");
+    EXPECT_EQ(1, client_->getZoneCount());
+}
+
+TEST_F(MemoryClientTest, getFileNameForNonExistentZone) {
+    // Zone "example.org." doesn't exist
+    EXPECT_TRUE(client_->getFileName(Name("example.org.")).empty());
+}
+
+TEST_F(MemoryClientTest, getFileName) {
+    client_->load(Name("example.org"), TEST_DATA_DIR "/example.org-empty.zone");
+    EXPECT_EQ(TEST_DATA_DIR "/example.org-empty.zone",
+              client_->getFileName(Name("example.org")));
+}
+
+TEST_F(MemoryClientTest, getIteratorForNonExistentZone) {
+    // Zone "." doesn't exist
+    EXPECT_THROW(client_->getIterator(Name(".")), DataSourceError);
+}
+
+TEST_F(MemoryClientTest, getIterator) {
+    client_->load(Name("example.org"), TEST_DATA_DIR "/example.org-empty.zone");
+    ZoneIteratorPtr iterator(client_->getIterator(Name("example.org")));
+
+    // First we have the SOA
+    ConstRRsetPtr rrset_soa(iterator->getNextRRset());
+    EXPECT_TRUE(rrset_soa);
+    EXPECT_EQ(RRType::SOA(), rrset_soa->getType());
+
+    // There's nothing else in this iterator
+    EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
+
+    // Iterating past the end should result in an exception
+    EXPECT_THROW(iterator->getNextRRset(), isc::Unexpected);
+}
+
+TEST_F(MemoryClientTest, getIteratorSeparateRRs) {
+    client_->load(Name("example.org"),
+                  TEST_DATA_DIR "/example.org-multiple.zone");
+
+    // separate_rrs = false
+    ZoneIteratorPtr iterator(client_->getIterator(Name("example.org")));
+
+    // First we have the SOA
+    ConstRRsetPtr rrset(iterator->getNextRRset());
+    EXPECT_TRUE(rrset);
+    EXPECT_EQ(RRType::SOA(), rrset->getType());
+
+    // Only one RRType::A() RRset
+    rrset = iterator->getNextRRset();
+    EXPECT_TRUE(rrset);
+    EXPECT_EQ(RRType::A(), rrset->getType());
+
+    // There's nothing else in this zone
+    EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
+
+
+    // separate_rrs = true
+    ZoneIteratorPtr iterator2(client_->getIterator(Name("example.org"), true));
+
+    // First we have the SOA
+    rrset = iterator2->getNextRRset();
+    EXPECT_TRUE(rrset);
+    EXPECT_EQ(RRType::SOA(), rrset->getType());
+
+    // First RRType::A() RRset
+    rrset = iterator2->getNextRRset();
+    EXPECT_TRUE(rrset);
+    EXPECT_EQ(RRType::A(), rrset->getType());
+
+    // Second RRType::A() RRset
+    rrset = iterator2->getNextRRset();
+    EXPECT_TRUE(rrset);
+    EXPECT_EQ(RRType::A(), rrset->getType());
+
+    // There's nothing else in this iterator
+    EXPECT_EQ(ConstRRsetPtr(), iterator2->getNextRRset());
+}
+
+TEST_F(MemoryClientTest, getIteratorGetSOAThrowsNotImplemented) {
+    client_->load(Name("example.org"), TEST_DATA_DIR "/example.org-empty.zone");
+    ZoneIteratorPtr iterator(client_->getIterator(Name("example.org")));
+
+    // This method is not implemented.
+    EXPECT_THROW(iterator->getSOA(), isc::NotImplemented);
+}
+
+TEST_F(MemoryClientTest, addRRsetToNonExistentZoneThrows) {
+    // The zone "example.org" doesn't exist, so we can't add an RRset to
+    // it.
+    RRsetPtr rrset_a(new RRset(Name("example.org"), RRClass::IN(), RRType::A(),
+                               RRTTL(300)));
+    rrset_a->addRdata(rdata::in::A("192.0.2.1"));
+    EXPECT_THROW(client_->add(Name("example.org"), rrset_a), DataSourceError);
+}
+
+TEST_F(MemoryClientTest, addOutOfZoneThrows) {
+    // Out of zone names should throw.
+    client_->load(Name("example.org"),
+                  TEST_DATA_DIR "/example.org-empty.zone");
+
+    RRsetPtr rrset_a(new RRset(Name("a.example.com"),
+                               RRClass::IN(), RRType::A(), RRTTL(300)));
+    rrset_a->addRdata(rdata::in::A("192.0.2.1"));
+
+    EXPECT_THROW(client_->add(Name("example.org"), rrset_a),
+                 OutOfZone);
+    // Teardown checks for memory segment leaks
+}
+
+TEST_F(MemoryClientTest, addNullRRsetThrows) {
+    client_->load(Name("example.org"),
+                  TEST_DATA_DIR "/example.org-rrsigs.zone");
+
+    EXPECT_THROW(client_->add(Name("example.org"), ConstRRsetPtr()),
+                 InMemoryClient::NullRRset);
+
+    // Teardown checks for memory segment leaks
+}
+
+TEST_F(MemoryClientTest, addEmptyRRsetThrows) {
+    client_->load(Name("example.org"),
+                  TEST_DATA_DIR "/example.org-rrsigs.zone");
+
+    RRsetPtr rrset_a(new RRset(Name("example.org"), RRClass::IN(), RRType::A(),
+                               RRTTL(300)));
+    EXPECT_THROW(client_->add(Name("example.org"), rrset_a),
+                 InMemoryClient::AddError);
+
+    // Teardown checks for memory segment leaks
+}
+
+TEST_F(MemoryClientTest, add) {
+    client_->load(Name("example.org"), TEST_DATA_DIR "/example.org-empty.zone");
+
+    // Add another RRset
+    RRsetPtr rrset_a(new RRset(Name("example.org"), RRClass::IN(), RRType::A(),
+                               RRTTL(300)));
+    rrset_a->addRdata(rdata::in::A("192.0.2.1"));
+    client_->add(Name("example.org"), rrset_a);
+
+    ZoneIteratorPtr iterator(client_->getIterator(Name("example.org")));
+
+    // First we have the SOA
+    ConstRRsetPtr rrset(iterator->getNextRRset());
+    EXPECT_TRUE(rrset);
+    EXPECT_EQ(RRType::A(), rrset->getType());
+
+    rrset = iterator->getNextRRset();
+    EXPECT_TRUE(rrset);
+    EXPECT_EQ(RRType::SOA(), rrset->getType());
+
+    // There's nothing else in this zone
+    EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
+}
+
+TEST_F(MemoryClientTest, findZoneData) {
+    client_->load(Name("example.org"),
+                  TEST_DATA_DIR "/example.org-rrsigs.zone");
+
+    const ZoneData* zone_data = client_->findZoneData(Name("example.com"));
+    EXPECT_EQ(static_cast<const ZoneData*>(NULL), zone_data);
+
+    zone_data = client_->findZoneData(Name("example.org"));
+    EXPECT_NE(static_cast<const ZoneData*>(NULL), zone_data);
+
+    /* Check SOA */
+    const ZoneNode* node = zone_data->getOriginNode();
+    EXPECT_NE(static_cast<const ZoneNode*>(NULL), node);
+
+    const RdataSet* set = node->getData();
+    EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
+    EXPECT_EQ(RRType::SOA(), set->type);
+
+    set = set->getNext();
+    EXPECT_EQ(static_cast<const RdataSet*>(NULL), set);
+
+    /* Check ns1.example.org */
+    const ZoneTree& tree = zone_data->getZoneTree();
+    ZoneTree::Result result3(tree.find(Name("ns1.example.org"), &node));
+    EXPECT_EQ(ZoneTree::EXACTMATCH, result3);
+    EXPECT_NE(static_cast<const ZoneNode*>(NULL), node);
+
+    set = node->getData();
+    EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
+    EXPECT_EQ(RRType::AAAA(), set->type);
+
+    set = set->getNext();
+    EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
+    EXPECT_EQ(RRType::A(), set->type);
+
+    set = set->getNext();
+    EXPECT_EQ(static_cast<const RdataSet*>(NULL), set);
+}
+
+TEST_F(MemoryClientTest, getUpdaterThrowsNotImplemented) {
+    // This method is not implemented.
+    EXPECT_THROW(client_->getUpdater(Name("."), false, false),
+                 isc::NotImplemented);
+}
+
+TEST_F(MemoryClientTest, getJournalReaderNotImplemented) {
+    // This method is not implemented.
+    EXPECT_THROW(client_->getJournalReader(Name("."), 0, 0),
+                 isc::NotImplemented);
+}
+}
diff --git a/src/lib/datasrc/tests/memory/memory_segment_test.h b/src/lib/datasrc/tests/memory/memory_segment_test.h
new file mode 100644
index 0000000..3195a9b
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/memory_segment_test.h
@@ -0,0 +1,62 @@
+// 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.
+
+#ifndef DATASRC_MEMORY_SEGMENT_TEST_H
+#define DATASRC_MEMORY_SEGMENT_TEST_H 1
+
+#include <util/memory_segment_local.h>
+
+#include <cstddef>              // for size_t
+#include <new>                  // for bad_alloc
+
+namespace isc {
+namespace datasrc {
+namespace memory {
+namespace test {
+
+// A special memory segment that can be used for tests.  It normally behaves
+// like a "local" memory segment.  If "throw count" is set to non 0 via
+// setThrowCount(), it continues the normal behavior until the specified
+// number of calls to allocate(), exclusive, and throws an exception at the
+// next call.  For example, if count is set to 3, the next two calls to
+// allocate() will succeed, and the 3rd call will fail with an exception.
+// This segment object can be used after the exception is thrown, and the
+// count is internally reset to 0.
+class MemorySegmentTest : public isc::util::MemorySegmentLocal {
+public:
+    MemorySegmentTest() : throw_count_(0) {}
+    virtual void* allocate(std::size_t size) {
+        if (throw_count_ > 0) {
+            if (--throw_count_ == 0) {
+                throw std::bad_alloc();
+            }
+        }
+        return (isc::util::MemorySegmentLocal::allocate(size));
+    }
+    void setThrowCount(std::size_t count) { throw_count_ = count; }
+
+private:
+    std::size_t throw_count_;
+};
+
+} // namespace test
+} // namespace memory
+} // namespace datasrc
+} // namespace isc
+
+#endif // DATASRC_MEMORY_SEGMENT_TEST_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/datasrc/tests/memory/rdata_serialization_unittest.cc b/src/lib/datasrc/tests/memory/rdata_serialization_unittest.cc
new file mode 100644
index 0000000..58c6cb1
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/rdata_serialization_unittest.cc
@@ -0,0 +1,839 @@
+// 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 <exceptions/exceptions.h>
+
+#include <util/buffer.h>
+
+#include <dns/name.h>
+#include <dns/labelsequence.h>
+#include <dns/messagerenderer.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+
+#include <datasrc/memory/rdata_serialization.h>
+
+#include <util/unittests/wiredata.h>
+
+#include <gtest/gtest.h>
+
+#include <boost/bind.hpp>
+#include <boost/foreach.hpp>
+
+#include <cstring>
+#include <set>
+#include <string>
+#include <vector>
+
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+using namespace isc::datasrc::memory;
+
+using isc::util::unittests::matchWireData;
+using std::string;
+using std::vector;
+
+// A trick to steal some private definitions of the implementation we use here
+
+namespace isc {
+namespace datasrc{
+namespace memory {
+
+#include <datasrc/memory/rdata_serialization_priv.cc>
+
+}
+}
+}
+
+namespace {
+// This defines a tuple of test data used in test_rdata_list below.
+struct TestRdata {
+    const char* const rrclass;  // RR class, textual form
+    const char* const rrtype;   // RR type, textual form
+    const char* const rdata;    // textual RDATA
+    const size_t n_varlen_fields; // expected # of variable-len fields
+};
+
+// This test data consist of (almost) all supported types of RDATA (+ some
+// unusual and corner cases).
+const TestRdata test_rdata_list[] = {
+    {"IN", "A", "192.0.2.1", 0},
+    {"IN", "NS", "ns.example.com", 0},
+    {"IN", "CNAME", "cname.example.com", 0},
+    {"IN", "SOA", "ns.example.com root.example.com 0 0 0 0 0", 0},
+    {"IN", "PTR", "reverse.example.com", 0},
+    {"IN", "HINFO", "\"cpu-info\" \"OS-info\"", 1},
+    {"IN", "MINFO", "root.example.com mbox.example.com", 0},
+    {"IN", "MX", "10 mx.example.com", 0},
+    {"IN", "TXT", "\"test1\" \"test 2\"", 1},
+    {"IN", "RP", "root.example.com. rp-text.example.com", 0},
+    {"IN", "AFSDB", "1 afsdb.example.com", 0},
+    {"IN", "AAAA", "2001:db8::1", 0},
+    {"IN", "SRV", "1 0 10 target.example.com", 0},
+    {"IN", "NAPTR", "100 50 \"s\" \"http\" \"\" _http._tcp.example.com", 1},
+    {"IN", "DNAME", "dname.example.com", 0},
+    {"IN", "DS", "12892 5 2 5F0EB5C777586DE18DA6B5", 1},
+    {"IN", "SSHFP", "1 1 dd465c09cfa51fb45020cc83316fff", 1},
+    // We handle RRSIG separately, so it's excluded from the list
+    {"IN", "NSEC", "next.example.com. A AAAA NSEC RRSIG", 1},
+    {"IN", "DNSKEY", "256 3 5 FAKEFAKE", 1},
+    {"IN", "DHCID", "FAKEFAKE", 1},
+    {"IN", "NSEC3", "1 1 12 AABBCCDD FAKEFAKE A RRSIG", 1},
+    {"IN", "NSEC3PARAM", "1 0 12 AABBCCDD", 1},
+    {"IN", "SPF", "v=spf1 +mx a:colo.example.com/28 -all", 1},
+    {"IN", "DLV", "12892 5 2 5F0EB5C777586DE18DA6B5", 1},
+    {"IN", "TYPE65000", "\\# 3 010203", 1}, // some "custom" type
+    {"IN", "TYPE65535", "\\# 0", 1},        // max RR type, 0-length RDATA
+    {"CH", "A", "\\# 2 0102", 1}, // A RR for non-IN class; varlen data
+    {"CH", "NS", "ns.example.com", 0}, // class CH, generic data
+    {"CH", "TXT", "BIND10", 1},        // ditto
+    {"HS", "A", "\\# 5 0102030405", 1}, // A RR for non-IN class; varlen data
+    {NULL, NULL, NULL, 0}
+};
+
+// The following two functions will be used to generate wire format data
+// from encoded representation of each RDATA.
+void
+renderNameField(MessageRenderer* renderer, bool additional_required,
+                const LabelSequence& labels, RdataNameAttributes attributes)
+{
+    EXPECT_EQ(additional_required, (attributes & NAMEATTR_ADDITIONAL) != 0);
+    renderer->writeName(labels, (attributes & NAMEATTR_COMPRESSIBLE) != 0);
+}
+
+void
+renderDataField(MessageRenderer* renderer, const void* data, size_t data_len) {
+    renderer->writeData(data, data_len);
+}
+
+class RdataSerializationTest : public ::testing::Test {
+protected:
+    RdataSerializationTest() : a_rdata_(createRdata(RRType::A(), RRClass::IN(),
+                                                    "192.0.2.53")),
+                         aaaa_rdata_(createRdata(RRType::AAAA(), RRClass::IN(),
+                                                 "2001:db8::53")),
+                         rrsig_rdata_(createRdata(
+                                          RRType::RRSIG(), RRClass::IN(),
+                                          "A 5 2 3600 20120814220826 "
+                                          "20120715220826 12345 com. FAKE"))
+    {}
+
+    // A wraper for RdataEncoder::encode() with buffer overrun check.
+    void encodeWrapper(size_t data_len);
+
+    // Some commonly used RDATA
+    const ConstRdataPtr a_rdata_;
+    const ConstRdataPtr aaaa_rdata_;
+    const ConstRdataPtr rrsig_rdata_;
+
+    RdataEncoder encoder_;
+    vector<uint8_t> encoded_data_;
+    MessageRenderer expected_renderer_;
+    MessageRenderer actual_renderer_;
+    vector<ConstRdataPtr> rdata_list_;
+};
+
+// There are several ways to decode the data. For one, there are
+// more interfaces uses for RdataReader, and we use our own decoder,
+// to check the actual encoded data.
+//
+// These decoding ways are provided by the template parameter.
+template<class DecoderStyle>
+class RdataEncodeDecodeTest : public RdataSerializationTest {
+public:
+    // This helper test method encodes the given list of RDATAs
+    // (in rdata_list), and then iterates over the data, rendering the fields
+    // in the wire format.  It then compares the wire data with the one
+    // generated by the normal libdns++ interface to see the encoding/decoding
+    // works as intended.
+    void checkEncode(RRClass rrclass, RRType rrtype,
+                     const vector<ConstRdataPtr>& rdata_list,
+                     size_t expected_varlen_fields,
+                     const vector<ConstRdataPtr>& rrsig_list =
+                     vector<ConstRdataPtr>());
+
+    void addRdataCommon(const vector<ConstRdataPtr>& rrsigs);
+    void addRdataMultiCommon(const vector<ConstRdataPtr>& rrsigs);
+};
+
+// Used across more classes and scopes. But it's just uninteresting
+// constant.
+const Name& dummyName2() {
+    static const Name result("example.com");
+    return (result);
+}
+
+bool
+additionalRequired(const RRType& type) {
+    // The set of RR types that require additional section processing.
+    // We'll use it to determine what value should the renderNameField get
+    // and, if the stored attributes are as expected.
+    static std::set<RRType> need_additionals;
+    if (need_additionals.empty()) {
+        need_additionals.insert(RRType::NS());
+        need_additionals.insert(RRType::MX());
+        need_additionals.insert(RRType::SRV());
+    }
+
+    return (need_additionals.find(type) != need_additionals.end());
+}
+
+// A decoder that does not use RdataReader. Not recommended for use,
+// but it allows the tests to check the internals of the data.
+class ManualDecoderStyle {
+public:
+    static void foreachRdataField(RRClass rrclass, RRType rrtype,
+                                  size_t rdata_count,
+                                  const vector<uint8_t>& encoded_data,
+                                  const vector<uint16_t>& varlen_list,
+                                  RdataReader::NameAction name_callback,
+                                  RdataReader::DataAction data_callback)
+    {
+        const RdataEncodeSpec& encode_spec = getRdataEncodeSpec(rrclass,
+                                                                rrtype);
+
+        size_t off = 0;
+        size_t varlen_count = 0;
+        size_t name_count = 0;
+        for (size_t count = 0; count < rdata_count; ++count) {
+            for (size_t i = 0; i < encode_spec.field_count; ++i) {
+                const RdataFieldSpec& field_spec = encode_spec.fields[i];
+                switch (field_spec.type) {
+                    case RdataFieldSpec::FIXEDLEN_DATA:
+                        if (data_callback) {
+                            data_callback(&encoded_data.at(off),
+                                          field_spec.fixeddata_len);
+                        }
+                        off += field_spec.fixeddata_len;
+                        break;
+                    case RdataFieldSpec::VARLEN_DATA:
+                        {
+                            const size_t varlen = varlen_list.at(varlen_count);
+                            if (data_callback && varlen > 0) {
+                                data_callback(&encoded_data.at(off), varlen);
+                            }
+                            off += varlen;
+                            ++varlen_count;
+                            break;
+                        }
+                    case RdataFieldSpec::DOMAIN_NAME:
+                        {
+                            ++name_count;
+                            const LabelSequence labels(&encoded_data.at(off));
+                            if (name_callback) {
+                                name_callback(labels,
+                                              field_spec.name_attributes);
+                            }
+                            off += labels.getSerializedLength();
+                            break;
+                        }
+                }
+            }
+        }
+        assert(name_count == encode_spec.name_count * rdata_count);
+        assert(varlen_count == encode_spec.varlen_count * rdata_count);
+    }
+
+    static void foreachRRSig(const vector<uint8_t>& encoded_data,
+                             const vector<uint16_t>& rrsiglen_list,
+                             RdataReader::DataAction data_callback)
+    {
+        size_t rrsig_totallen = 0;
+        for (vector<uint16_t>::const_iterator it = rrsiglen_list.begin();
+             it != rrsiglen_list.end();
+             ++it) {
+            rrsig_totallen += *it;
+        }
+        assert(encoded_data.size() >= rrsig_totallen);
+
+        const uint8_t* dp = &encoded_data[encoded_data.size() -
+            rrsig_totallen];
+        for (size_t i = 0; i < rrsiglen_list.size(); ++i) {
+            data_callback(dp, rrsiglen_list[i]);
+            dp += rrsiglen_list[i];
+        }
+    }
+
+    static void decode(const isc::dns::RRClass& rrclass,
+                       const isc::dns::RRType& rrtype,
+                       size_t rdata_count,
+                       size_t rrsig_count,
+                       size_t expected_varlen_fields,
+                       // Warning: this test actualy might change the
+                       // encoded_data !
+                       vector<uint8_t>& encoded_data, size_t,
+                       MessageRenderer& renderer)
+    {
+        // If this type of RDATA is expected to contain variable-length fields,
+        // we brute force the encoded data, exploiting our knowledge of actual
+        // encoding, then adjust the encoded data excluding the list of length
+        // fields.  This is ugly, but for tests only.
+        vector<uint16_t> varlen_list;
+        if (expected_varlen_fields > 0) {
+            const size_t varlen_list_size =
+                rdata_count * expected_varlen_fields * sizeof(uint16_t);
+            ASSERT_LE(varlen_list_size, encoded_data.size());
+            varlen_list.resize(rdata_count * expected_varlen_fields);
+            std::memcpy(&varlen_list[0], &encoded_data[0], varlen_list_size);
+            encoded_data.assign(encoded_data.begin() + varlen_list_size,
+                                encoded_data.end());
+        }
+
+        // If RRSIGs are given, we need to extract the list of the RRSIG
+        // lengths and adjust encoded_data_ further.
+        vector<uint16_t> rrsiglen_list;
+        if (rrsig_count > 0) {
+            const size_t rrsig_len_size = rrsig_count * sizeof(uint16_t);
+            ASSERT_LE(rrsig_len_size, encoded_data.size());
+            rrsiglen_list.resize(rrsig_count * rrsig_len_size);
+            std::memcpy(&rrsiglen_list[0], &encoded_data[0], rrsig_len_size);
+            encoded_data.assign(encoded_data.begin() + rrsig_len_size,
+                                encoded_data.end());
+        }
+
+        // Create wire-format data from the encoded data
+        foreachRdataField(rrclass, rrtype, rdata_count, encoded_data,
+                          varlen_list,
+                          boost::bind(renderNameField, &renderer,
+                                      additionalRequired(rrtype), _1, _2),
+                          boost::bind(renderDataField, &renderer, _1, _2));
+
+        // 2nd dummy name
+        renderer.writeName(dummyName2());
+        // Finally, dump any RRSIGs in wire format.
+        foreachRRSig(encoded_data, rrsiglen_list,
+                     boost::bind(renderDataField, &renderer, _1, _2));
+    }
+};
+
+// Check using callbacks and calling next until the end.
+class CallbackDecoder {
+public:
+    static void decode(const isc::dns::RRClass& rrclass,
+                       const isc::dns::RRType& rrtype,
+                       size_t rdata_count, size_t sig_count, size_t,
+                       const vector<uint8_t>& encoded_data, size_t,
+                       MessageRenderer& renderer)
+    {
+        RdataReader reader(rrclass, rrtype, &encoded_data[0], rdata_count,
+                           sig_count,
+                           boost::bind(renderNameField, &renderer,
+                                       additionalRequired(rrtype), _1, _2),
+                           boost::bind(renderDataField, &renderer, _1, _2));
+        while (reader.next() != RdataReader::RRSET_BOUNDARY) {}
+        renderer.writeName(dummyName2());
+        while (reader.nextSig() != RdataReader::RRSET_BOUNDARY) {}
+    }
+};
+
+// Check using callbacks and calling iterate.
+class IterateDecoder {
+public:
+    static void decode(const isc::dns::RRClass& rrclass,
+                       const isc::dns::RRType& rrtype,
+                       size_t rdata_count, size_t sig_count, size_t,
+                       const vector<uint8_t>& encoded_data, size_t,
+                       MessageRenderer& renderer)
+    {
+        RdataReader reader(rrclass, rrtype, &encoded_data[0],
+                           rdata_count, sig_count,
+                           boost::bind(renderNameField, &renderer,
+                                       additionalRequired(rrtype), _1, _2),
+                           boost::bind(renderDataField, &renderer, _1, _2));
+        reader.iterate();
+        renderer.writeName(dummyName2());
+        reader.iterateAllSigs();
+    }
+};
+
+namespace {
+
+// Render the data to renderer, if one is set, or put it inside
+// a data buffer.
+void
+appendOrRenderData(vector<uint8_t>* where, MessageRenderer** renderer,
+                   const void* data, size_t size)
+{
+    if (*renderer != NULL) {
+        (*renderer)->writeData(data, size);
+    } else {
+        where->insert(where->end(), reinterpret_cast<const uint8_t*>(data),
+                      reinterpret_cast<const uint8_t*>(data) + size);
+    }
+}
+
+}
+
+// Similar to IterateDecoder, but it first iterates a little and rewinds
+// before actual rendering.
+class RewindAndDecode {
+private:
+    static void writeName(MessageRenderer** renderer,
+                          const LabelSequence& labels,
+                          RdataNameAttributes attributes)
+    {
+        (*renderer)->writeName(labels,
+                               (attributes & NAMEATTR_COMPRESSIBLE) != 0);
+    }
+public:
+    static void decode(const isc::dns::RRClass& rrclass,
+                       const isc::dns::RRType& rrtype,
+                       size_t rdata_count, size_t sig_count, size_t,
+                       const vector<uint8_t>& encoded_data, size_t,
+                       MessageRenderer& renderer)
+    {
+        MessageRenderer dump; // A place to dump the extra data from before
+                              // actual rendering.
+        MessageRenderer* current = &dump;
+        vector<uint8_t> placeholder; // boost::bind does not like NULL
+        RdataReader reader(rrclass, rrtype, &encoded_data[0],
+                           rdata_count, sig_count,
+                           boost::bind(writeName, &current, _1, _2),
+                           boost::bind(appendOrRenderData, &placeholder,
+                                       &current, _1, _2));
+        // Iterate a little and rewind
+        reader.next();
+        reader.nextSig();
+        reader.rewind();
+        // Do the actual rendering
+        current = &renderer;
+        reader.iterate();
+        renderer.writeName(dummyName2());
+        reader.iterateAllSigs();
+    }
+};
+
+// Decode using the iteration over one rdata each time.
+// We also count there's the correct count of Rdatas.
+class SingleIterateDecoder {
+public:
+    static void decode(const isc::dns::RRClass& rrclass,
+                       const isc::dns::RRType& rrtype,
+                       size_t rdata_count, size_t sig_count, size_t,
+                       const vector<uint8_t>& encoded_data, size_t,
+                       MessageRenderer& renderer)
+    {
+        RdataReader reader(rrclass, rrtype, &encoded_data[0],
+                           rdata_count, sig_count,
+                           boost::bind(renderNameField, &renderer,
+                                       additionalRequired(rrtype), _1, _2),
+                           boost::bind(renderDataField, &renderer, _1, _2));
+        size_t actual_count = 0;
+        while (reader.iterateRdata()) {
+            ++actual_count;
+        }
+        EXPECT_EQ(rdata_count, actual_count);
+        actual_count = 0;
+        renderer.writeName(dummyName2());
+        while (reader.iterateSingleSig()) {
+            ++actual_count;
+        }
+        EXPECT_EQ(sig_count, actual_count);
+    }
+};
+
+// This one does not adhere to the usual way the reader is used, trying
+// to confuse it. It iterates part of the data manually and then reads
+// the rest through iterate. It also reads the signatures in the middle
+// of rendering.
+template<bool start_data, bool start_sig>
+class HybridDecoder {
+public:
+    static void decode(const isc::dns::RRClass& rrclass,
+                       const isc::dns::RRType& rrtype,
+                       size_t rdata_count, size_t sig_count, size_t,
+                       const vector<uint8_t>& encoded_data,
+                       size_t encoded_data_len,
+                       MessageRenderer& renderer)
+    {
+        vector<uint8_t> data;
+        MessageRenderer* current;
+        RdataReader reader(rrclass, rrtype, &encoded_data[0],
+                           rdata_count, sig_count,
+                           boost::bind(renderNameField, &renderer,
+                                       additionalRequired(rrtype), _1, _2),
+                           boost::bind(appendOrRenderData, &data, &current, _1,
+                                       _2));
+        // The size matches
+        EXPECT_EQ(encoded_data_len, reader.getSize());
+        if (start_sig) {
+            current = NULL;
+            reader.nextSig();
+        }
+        // Render first part of data. If there's none, return empty Result and
+        // do nothing.
+        if (start_data) {
+            current = &renderer;
+            reader.next();
+        }
+        // Now, we let all sigs to be copied to data. We disable the
+        // renderer for this.
+        current = NULL;
+        reader.iterateAllSigs();
+        // Now return the renderer and render the rest of the data
+        current = &renderer;
+        reader.iterate();
+        // Now, this should not break anything and should be valid, but should
+        // return ends.
+        EXPECT_EQ(RdataReader::RRSET_BOUNDARY, reader.next());
+        EXPECT_EQ(RdataReader::RRSET_BOUNDARY, reader.nextSig());
+        // Render the name and the sigs
+        renderer.writeName(dummyName2());
+        renderer.writeData(&data[0], data.size());
+        // The size matches even after use
+        EXPECT_EQ(encoded_data_len, reader.getSize());
+    }
+};
+
+typedef ::testing::Types<ManualDecoderStyle,
+                         CallbackDecoder, IterateDecoder, SingleIterateDecoder,
+                         HybridDecoder<true, true>, HybridDecoder<true, false>,
+                         HybridDecoder<false, true>,
+                         HybridDecoder<false, false> >
+    DecoderStyles;
+// Each decoder style must contain a decode() method. Such method is expected
+// to decode the passed data, first render the Rdata into the passed renderer,
+// then write the dummyName2() there and write the RRSig data after that.
+// It may do other checks too.
+//
+// There are some slight differences to how to do the decoding, that's why we
+// have the typed test.
+TYPED_TEST_CASE(RdataEncodeDecodeTest, DecoderStyles);
+
+void
+RdataSerializationTest::encodeWrapper(size_t data_len) {
+    // make sure the data buffer is large enough for the canary
+    encoded_data_.resize(data_len + 2);
+    // set the canary data
+    encoded_data_.at(data_len) = 0xde;
+    encoded_data_.at(data_len + 1) = 0xad;
+    // encode, then check the canary is intact
+    encoder_.encode(&encoded_data_[0], data_len);
+    EXPECT_EQ(0xde, encoded_data_.at(data_len));
+    EXPECT_EQ(0xad, encoded_data_.at(data_len + 1));
+    // shrink the data buffer to the originally expected size (some tests
+    // expect that).  the actual encoded data should be intact.
+    encoded_data_.resize(data_len);
+}
+
+template<class DecoderStyle>
+void
+RdataEncodeDecodeTest<DecoderStyle>::
+checkEncode(RRClass rrclass, RRType rrtype,
+            const vector<ConstRdataPtr>& rdata_list,
+            size_t expected_varlen_fields,
+            const vector<ConstRdataPtr>& rrsig_list)
+{
+    // These two names will be rendered before and after the test RDATA,
+    // to check in case the RDATA contain a domain name whether it's
+    // compressed or not correctly.  The names in the RDATA should basically
+    // a subdomain of example.com, so it can be compressed due to dummyName2().
+    // Likewise, dummyName2() should be able to be fully compressed due to
+    // the name in the RDATA.
+    const Name dummy_name("com");
+
+    expected_renderer_.clear();
+    actual_renderer_.clear();
+    encoded_data_.clear();
+
+    // Build expected wire-format data
+    expected_renderer_.writeName(dummy_name);
+    BOOST_FOREACH(const ConstRdataPtr& rdata, rdata_list) {
+        rdata->toWire(expected_renderer_);
+    }
+    expected_renderer_.writeName(dummyName2());
+    BOOST_FOREACH(const ConstRdataPtr& rdata, rrsig_list) {
+        rdata->toWire(expected_renderer_);
+    }
+
+    // Then build wire format data using the encoded data.
+    // 1st dummy name
+    actual_renderer_.writeName(dummy_name);
+
+    // Create encoded data
+    encoder_.start(rrclass, rrtype);
+    BOOST_FOREACH(const ConstRdataPtr& rdata, rdata_list) {
+        encoder_.addRdata(*rdata);
+    }
+    BOOST_FOREACH(const ConstRdataPtr& rdata, rrsig_list) {
+        encoder_.addSIGRdata(*rdata);
+    }
+    const size_t storage_len = encoder_.getStorageLength();
+    encodeWrapper(storage_len);
+
+    DecoderStyle::decode(rrclass, rrtype, rdata_list.size(), rrsig_list.size(),
+                         expected_varlen_fields, encoded_data_, storage_len,
+                         actual_renderer_);
+
+    // Two sets of wire-format data should be identical.
+    matchWireData(expected_renderer_.getData(), expected_renderer_.getLength(),
+                  actual_renderer_.getData(), actual_renderer_.getLength());
+}
+
+template<class DecoderStyle>
+void
+RdataEncodeDecodeTest<DecoderStyle>::
+addRdataCommon(const vector<ConstRdataPtr>& rrsigs) {
+    // Basic check on the encoded data for (most of) all supported RR types,
+    // in a comprehensive manner.
+    for (size_t i = 0; test_rdata_list[i].rrclass != NULL; ++i) {
+        SCOPED_TRACE(string(test_rdata_list[i].rrclass) + "/" +
+                     test_rdata_list[i].rrtype);
+        const RRClass rrclass(test_rdata_list[i].rrclass);
+        const RRType rrtype(test_rdata_list[i].rrtype);
+        const ConstRdataPtr rdata = createRdata(rrtype, rrclass,
+                                                test_rdata_list[i].rdata);
+        rdata_list_.clear();
+        rdata_list_.push_back(rdata);
+        checkEncode(rrclass, rrtype, rdata_list_,
+                    test_rdata_list[i].n_varlen_fields, rrsigs);
+    }
+}
+
+TYPED_TEST(RdataEncodeDecodeTest, addRdata) {
+    vector<ConstRdataPtr> rrsigs;
+    this->addRdataCommon(rrsigs); // basic tests without RRSIGs (empty vector)
+
+    // Test with RRSIGs (covered type doesn't always match, but the encoder
+    // doesn't check that)
+    rrsigs.push_back(this->rrsig_rdata_);
+    this->addRdataCommon(rrsigs);
+}
+
+template<class DecoderStyle>
+void
+RdataEncodeDecodeTest<DecoderStyle>::
+addRdataMultiCommon(const vector<ConstRdataPtr>& rrsigs) {
+    // Similar to addRdata(), but test with multiple RDATAs.
+    // Four different cases are tested: a single fixed-len RDATA (A),
+    // fixed-len data + domain name (MX), variable-len data only (TXT),
+    // variable-len data + domain name (NAPTR).
+    ConstRdataPtr a_rdata2 = createRdata(RRType::A(), RRClass::IN(),
+                                         "192.0.2.54");
+    rdata_list_.clear();
+    rdata_list_.push_back(a_rdata_);
+    rdata_list_.push_back(a_rdata2);
+    checkEncode(RRClass::IN(), RRType::A(), rdata_list_, 0, rrsigs);
+
+    ConstRdataPtr mx_rdata1 = createRdata(RRType::MX(), RRClass::IN(),
+                                          "5 mx1.example.com");
+    ConstRdataPtr mx_rdata2 = createRdata(RRType::MX(), RRClass::IN(),
+                                          "10 mx2.example.com");
+    rdata_list_.clear();
+    rdata_list_.push_back(mx_rdata1);
+    rdata_list_.push_back(mx_rdata2);
+    checkEncode(RRClass::IN(), RRType::MX(), rdata_list_, 0, rrsigs);
+
+    ConstRdataPtr txt_rdata1 = createRdata(RRType::TXT(), RRClass::IN(),
+                                           "foo bar baz");
+    ConstRdataPtr txt_rdata2 = createRdata(RRType::TXT(), RRClass::IN(),
+                                          "another text data");
+    rdata_list_.clear();
+    rdata_list_.push_back(txt_rdata1);
+    rdata_list_.push_back(txt_rdata2);
+    checkEncode(RRClass::IN(), RRType::TXT(), rdata_list_, 1, rrsigs);
+
+    ConstRdataPtr naptr_rdata1 =
+        createRdata(RRType::NAPTR(), RRClass::IN(),
+                    "100 50 \"s\" \"http\" \"\" _http._tcp.example.com");
+    ConstRdataPtr naptr_rdata2 =
+        createRdata(RRType::NAPTR(), RRClass::IN(),
+                    "200 100 \"s\" \"http\" \"\" _http._tcp.example.com");
+    rdata_list_.clear();
+    rdata_list_.push_back(naptr_rdata1);
+    rdata_list_.push_back(naptr_rdata2);
+    checkEncode(RRClass::IN(), RRType::NAPTR(), rdata_list_, 1, rrsigs);
+}
+
+void ignoreName(const LabelSequence&, unsigned) {
+}
+
+void
+checkLargeData(const in::DHCID* decoded, bool* called, const void* encoded,
+               size_t length)
+{
+    EXPECT_FALSE(*called); // Called exactly once
+    *called = true;
+
+    // Reconstruct the Rdata and check it.
+    isc::util::InputBuffer ib(encoded, length);
+    const in::DHCID reconstructed(ib, ib.getLength());
+    EXPECT_EQ(0, reconstructed.compare(*decoded));
+}
+
+TEST_F(RdataSerializationTest, encodeLargeRdata) {
+    // There should be no reason for a large RDATA to fail in encoding,
+    // but we check such a case explicitly.
+
+    encoded_data_.resize(65535); // max unsigned 16-bit int
+    isc::util::InputBuffer buffer(&encoded_data_[0], encoded_data_.size());
+    const in::DHCID large_dhcid(buffer, encoded_data_.size());
+
+    encoder_.start(RRClass::IN(), RRType::DHCID());
+    encoder_.addRdata(large_dhcid);
+    encodeWrapper(encoder_.getStorageLength());
+
+    // The encoded data should be identical to the original one.
+    bool called = false;
+    RdataReader reader(RRClass::IN(), RRType::DHCID(), &encoded_data_[0], 1, 0,
+                       ignoreName, boost::bind(checkLargeData, &large_dhcid,
+                                               &called, _1, _2));
+    reader.iterate();
+    EXPECT_TRUE(called);
+    called = false;
+    reader.iterateAllSigs();
+    EXPECT_FALSE(called);
+}
+
+TYPED_TEST(RdataEncodeDecodeTest, addRdataMulti) {
+    vector<ConstRdataPtr> rrsigs;
+    this->addRdataMultiCommon(rrsigs); // test without RRSIGs (empty vector)
+
+    // Tests with two RRSIGs
+    rrsigs.push_back(this->rrsig_rdata_);
+    rrsigs.push_back(createRdata(RRType::RRSIG(), RRClass::IN(),
+                                 "A 5 2 3600 20120814220826 "
+                                 "20120715220826 54321 com. FAKE"));
+    this->addRdataMultiCommon(rrsigs);
+}
+
+TEST_F(RdataSerializationTest, badAddRdata) {
+    // Some operations must follow start().
+    EXPECT_THROW(encoder_.addRdata(*a_rdata_), isc::InvalidOperation);
+    EXPECT_THROW(encoder_.getStorageLength(), isc::InvalidOperation);
+    // will allocate space of some arbitrary size (256 bytes)
+    EXPECT_THROW(encodeWrapper(256), isc::InvalidOperation);
+
+    // Bad buffer for encode
+    encoder_.start(RRClass::IN(), RRType::A());
+    encoder_.addRdata(*a_rdata_);
+    const size_t buf_len = encoder_.getStorageLength();
+    // NULL buffer for encode
+    EXPECT_THROW(encoder_.encode(NULL, buf_len), isc::BadValue);
+    // buffer length is too short (we don't use the wrraper because we don't
+    // like to tweak the length arg to encode()).
+    encoded_data_.resize(buf_len - 1);
+    EXPECT_THROW(encoder_.encode(&encoded_data_[0], buf_len - 1),
+                 isc::BadValue);
+
+    // Type of RDATA and the specified RR type don't match.  addRdata() should
+    // detect this inconsistency.
+    encoder_.start(RRClass::IN(), RRType::AAAA());
+    EXPECT_THROW(encoder_.addRdata(*a_rdata_), isc::BadValue);
+
+    // Likewise.
+    encoder_.start(RRClass::IN(), RRType::A());
+    EXPECT_THROW(encoder_.addRdata(*aaaa_rdata_), isc::BadValue);
+
+    // Likewise.  The encoder expects the first name completes the data, and
+    // throws on the second due as an unexpected name field.
+    const ConstRdataPtr rp_rdata =
+        createRdata(RRType::RP(), RRClass::IN(), "a.example. b.example");
+    encoder_.start(RRClass::IN(), RRType::NS());
+    EXPECT_THROW(encoder_.addRdata(*rp_rdata), isc::BadValue);
+
+    // Likewise.  The encoder considers the name data a variable length data
+    // field, and throws on the first name.
+    encoder_.start(RRClass::IN(), RRType::DHCID());
+    EXPECT_THROW(encoder_.addRdata(*rp_rdata), isc::BadValue);
+
+    // Likewise.  The text RDATA (2 bytes) will be treated as MX preference,
+    // and the encoder will still expect to see a domain name.
+    const ConstRdataPtr txt_rdata = createRdata(RRType::TXT(), RRClass::IN(),
+                                                "a");
+    encoder_.start(RRClass::IN(), RRType::MX());
+    EXPECT_THROW(encoder_.addRdata(*txt_rdata), isc::BadValue);
+
+    // Similar to the previous one, but in this case there's no data field
+    // in the spec.
+    encoder_.start(RRClass::IN(), RRType::NS());
+    EXPECT_THROW(encoder_.addRdata(*txt_rdata), isc::BadValue);
+
+    // Likewise.  Inconsistent name compression policy.
+    const ConstRdataPtr ns_rdata =
+        createRdata(RRType::NS(), RRClass::IN(), "ns.example");
+    encoder_.start(RRClass::IN(), RRType::DNAME());
+    EXPECT_THROW(encoder_.addRdata(*ns_rdata), isc::BadValue);
+
+    // Same as the previous one, opposite inconsistency.
+    const ConstRdataPtr dname_rdata =
+        createRdata(RRType::DNAME(), RRClass::IN(), "dname.example");
+    encoder_.start(RRClass::IN(), RRType::NS());
+    EXPECT_THROW(encoder_.addRdata(*dname_rdata), isc::BadValue);
+
+    // RDATA len exceeds the 16-bit range.  Technically not invalid, but
+    // we don't support that (and it's practically useless anyway).
+    encoded_data_.resize(65536); // use encoded_data_ for placeholder
+    isc::util::InputBuffer buffer(&encoded_data_[0], encoded_data_.size());
+    encoder_.start(RRClass::IN(), RRType::DHCID());
+    EXPECT_THROW(encoder_.addRdata(in::DHCID(buffer, encoded_data_.size())),
+                                   RdataEncodingError);
+
+    // RRSIG cannot be used as the main RDATA type (can only be added as
+    // a signature for some other type of RDATAs).
+    EXPECT_THROW(encoder_.start(RRClass::IN(), RRType::RRSIG()),
+                 isc::BadValue);
+}
+
+void
+checkSigData(const ConstRdataPtr& decoded, bool* called, const void* encoded,
+             size_t length)
+{
+    EXPECT_FALSE(*called); // Called exactly once
+    *called = true;
+
+    // Reconstruct the RRSig and check it.
+    isc::util::InputBuffer ib(encoded, length);
+    const generic::RRSIG reconstructed(ib, ib.getLength());
+    EXPECT_EQ(0, reconstructed.compare(*decoded));
+}
+
+TEST_F(RdataSerializationTest, addSIGRdataOnly) {
+    // Encoded data that only contain RRSIGs.  Mostly useless, but can happen
+    // (in a partially broken zone) and it's accepted.
+    encoder_.start(RRClass::IN(), RRType::A());
+    encoder_.addSIGRdata(*rrsig_rdata_);
+    encodeWrapper(encoder_.getStorageLength());
+    ASSERT_LT(sizeof(uint16_t), encoder_.getStorageLength());
+
+    bool called = false;
+    RdataReader reader(RRClass::IN(), RRType::A(), &encoded_data_[0], 0, 1,
+                       ignoreName, boost::bind(checkSigData, rrsig_rdata_,
+                                               &called, _1, _2));
+    reader.iterate();
+    EXPECT_FALSE(called);
+    reader.iterateAllSigs();
+    EXPECT_TRUE(called);
+}
+
+TEST_F(RdataSerializationTest, badAddSIGRdata) {
+    // try adding SIG before start
+    EXPECT_THROW(encoder_.addSIGRdata(*rrsig_rdata_), isc::InvalidOperation);
+
+    // Very big RRSIG.  This implementation rejects it.
+    isc::util::OutputBuffer ob(0);
+    rrsig_rdata_->toWire(ob);
+    // append dummy trailing signature to make it too big
+    vector<uint8_t> dummy_sig(65536 - ob.getLength());
+    ob.writeData(&dummy_sig[0], dummy_sig.size());
+    ASSERT_EQ(65536, ob.getLength());
+
+    isc::util::InputBuffer ib(ob.getData(), ob.getLength());
+    const generic::RRSIG big_sigrdata(ib, ob.getLength());
+    encoder_.start(RRClass::IN(), RRType::A());
+    EXPECT_THROW(encoder_.addSIGRdata(big_sigrdata), RdataEncodingError);
+}
+}
diff --git a/src/lib/datasrc/tests/memory/rdataset_unittest.cc b/src/lib/datasrc/tests/memory/rdataset_unittest.cc
new file mode 100644
index 0000000..897e53c
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/rdataset_unittest.cc
@@ -0,0 +1,298 @@
+// 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 <exceptions/exceptions.h>
+
+#include <util/buffer.h>
+#include <util/memory_segment_local.h>
+
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rrset.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+#include <dns/rrttl.h>
+
+#include <datasrc/memory/rdata_serialization.h>
+#include <datasrc/memory/rdataset.h>
+
+#include <testutils/dnsmessage_test.h>
+
+#include <gtest/gtest.h>
+
+#include <boost/lexical_cast.hpp>
+
+#include <string>
+
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+using namespace isc::datasrc::memory;
+using namespace isc::testutils;
+using boost::lexical_cast;
+
+namespace {
+
+class RdataSetTest : public ::testing::Test {
+protected:
+    RdataSetTest() :
+        // 1076895760 = 0x40302010.  Use this so we fill in all 8-bit "field"
+        // of the 32-bit TTL
+        a_rrset_(textToRRset("www.example.com. 1076895760 IN A 192.0.2.1")),
+        rrsig_rrset_(textToRRset("www.example.com. 1076895760 IN RRSIG "
+                                 "A 5 2 3600 20120814220826 20120715220826 "
+                                 "1234 example.com. FAKE"))
+    {}
+    void TearDown() {
+        EXPECT_TRUE(mem_sgmt_.allMemoryDeallocated());
+    }
+
+    ConstRRsetPtr a_rrset_, rrsig_rrset_;
+    isc::util::MemorySegmentLocal mem_sgmt_;
+    RdataEncoder encoder_;
+};
+
+// Convert the given 32-bit integer (network byte order) to the corresponding
+// RRTTL object.
+RRTTL
+restoreTTL(const void* ttl_data) {
+    isc::util::InputBuffer b(ttl_data, sizeof(uint32_t));
+    return (RRTTL(b));
+}
+
+// A helper callback for checkRdataSet.  This confirms the given data
+// is the expected in::A RDATA (the value is taken from the RdataSetTest
+// constructor).
+void
+checkData(const void* data, size_t size) {
+    isc::util::InputBuffer b(data, size);
+    EXPECT_EQ(0, in::A(b, size).compare(in::A("192.0.2.1")));
+}
+
+// This is a set of checks for an RdataSet created with some simple
+// conditions.  with_rrset/with_rrsig is true iff the RdataSet is supposed to
+// contain normal/RRSIG RDATA.
+void
+checkRdataSet(const RdataSet& rdataset, bool with_rrset, bool with_rrsig) {
+    EXPECT_FALSE(rdataset.next); // by default the next pointer should be NULL
+    EXPECT_EQ(RRType::A(), rdataset.type);
+    // See the RdataSetTest constructor for the magic number.
+    EXPECT_EQ(RRTTL(1076895760), restoreTTL(rdataset.getTTLData()));
+    EXPECT_EQ(with_rrset ? 1 : 0, rdataset.getRdataCount());
+    EXPECT_EQ(with_rrsig ? 1 : 0, rdataset.getSigRdataCount());
+
+    // A simple test for the data content.  Details tests for the encoder/
+    // reader should be basically sufficient for various cases of the data,
+    // and the fact that this test doesn't detect memory leak should be
+    // reasonably sufficient that the implementation handles the data region
+    // correctly.  Here we check one simple case for a simple form of RDATA,
+    // mainly for checking the behavior of getDataBuf().
+    RdataReader reader(RRClass::IN(), RRType::A(),
+                       reinterpret_cast<const uint8_t*>(
+                           rdataset.getDataBuf()),
+                       rdataset.getRdataCount(), rdataset.getSigRdataCount(),
+                       &RdataReader::emptyNameAction, checkData);
+    reader.iterate();
+}
+
+TEST_F(RdataSetTest, create) {
+    // A simple case of creating an RdataSet.  Confirming the resulting
+    // fields have the expected values, and then destroying it (TearDown()
+    // would detect any memory leak)
+    RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
+                                          ConstRRsetPtr());
+    checkRdataSet(*rdataset, true, false);
+    RdataSet::destroy(mem_sgmt_, RRClass::IN(), rdataset);
+}
+
+TEST_F(RdataSetTest, getNext) {
+    RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
+                                          ConstRRsetPtr());
+
+    // By default, the next pointer should be NULL (already tested in other
+    // test cases), which should be the case with getNext().  We test both
+    // mutable and immutable versions of getNext().
+    EXPECT_EQ(static_cast<RdataSet*>(NULL), rdataset->getNext());
+    EXPECT_EQ(static_cast<const RdataSet*>(NULL),
+              static_cast<const RdataSet*>(rdataset)->getNext());
+
+    // making a link (it would form an infinite loop, but it doesn't matter
+    // in this test), and check the pointer returned by getNext().
+    rdataset->next = rdataset;
+    EXPECT_EQ(rdataset, static_cast<const RdataSet*>(rdataset)->getNext());
+
+    RdataSet::destroy(mem_sgmt_, RRClass::IN(), rdataset);
+}
+
+// A helper function to create an RRset containing the given number of
+// unique RDATAs.
+ConstRRsetPtr
+getRRsetWithRdataCount(size_t rdata_count) {
+    RRsetPtr rrset(new RRset(Name("example.com"), RRClass::IN(), RRType::TXT(),
+                             RRTTL(3600)));
+    for (size_t i = 0; i < rdata_count; ++i) {
+        rrset->addRdata(rdata::createRdata(RRType::TXT(), RRClass::IN(),
+                                           lexical_cast<std::string>(i)));
+    }
+    return (rrset);
+}
+
+TEST_F(RdataSetTest, createManyRRs) {
+    // RRset with possible maximum number of RDATAs
+    RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder_,
+                                          getRRsetWithRdataCount(8191),
+                                          ConstRRsetPtr());
+    EXPECT_EQ(8191, rdataset->getRdataCount());
+    EXPECT_EQ(0, rdataset->getSigRdataCount());
+    RdataSet::destroy(mem_sgmt_, RRClass::IN(), rdataset);
+
+    // Exceeding that will result in an exception.
+    EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_,
+                                  getRRsetWithRdataCount(8192),
+                                  ConstRRsetPtr()),
+                 RdataSetError);
+    // To be very sure even try larger number than the threshold
+    EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_,
+                                  getRRsetWithRdataCount(65535),
+                                  ConstRRsetPtr()),
+                 RdataSetError);
+}
+
+TEST_F(RdataSetTest, createWithRRSIG) {
+    // Normal case.
+    RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
+                                          rrsig_rrset_);
+    checkRdataSet(*rdataset, true, true);
+    RdataSet::destroy(mem_sgmt_, RRClass::IN(), rdataset);
+
+    // Unusual case: TTL doesn't match.  This implementation accepts that,
+    // using the TTL of the covered RRset.
+    ConstRRsetPtr rrsig_badttl(textToRRset(
+                                   "www.example.com. 3600 IN RRSIG "
+                                   "A 5 2 3600 20120814220826 "
+                                   "20120715220826 1234 example.com. FAKE"));
+    rdataset = RdataSet::create(mem_sgmt_, encoder_, a_rrset_, rrsig_badttl);
+    checkRdataSet(*rdataset, true, true);
+    RdataSet::destroy(mem_sgmt_, RRClass::IN(), rdataset);
+}
+
+// A helper function to create an RRSIG RRset containing the given number of
+// unique RDATAs.
+ConstRRsetPtr
+getRRSIGWithRdataCount(size_t sig_count) {
+    RRsetPtr rrset(new RRset(Name("example.com"), RRClass::IN(),
+                             RRType::RRSIG(), RRTTL(3600)));
+    // We use a base wire-format image and tweak the original TTL field to
+    // generate unique RDATAs in the loop.  (Creating them from corresponding
+    // text is simpler, but doing so for a large number of RRSIGs is
+    // relatively heavy and could be too long for unittests).
+    ConstRdataPtr rrsig_base =
+        rdata::createRdata(RRType::RRSIG(), RRClass::IN(),
+                           "A 5 2 3600 20120814220826 20120715220826 1234 "
+                           "example.com. FAKE");
+    isc::util::OutputBuffer ob(0);
+    rrsig_base->toWire(ob);
+    for (size_t i = 0; i < sig_count; ++i) {
+        ob.writeUint16At((i >> 16) & 0xffff, 4);
+        ob.writeUint16At(i & 0xffff, 6);
+        isc::util::InputBuffer ib(ob.getData(), ob.getLength());
+        rrset->addRdata(rdata::createRdata(RRType::RRSIG(), RRClass::IN(),
+                                           ib, ib.getLength()));
+    }
+    return (rrset);
+}
+
+TEST_F(RdataSetTest, createManyRRSIGs) {
+    // 7 has a special meaning in the implementation: if the number of the
+    // RRSIGs reaches this value, an extra 'sig count' field will be created.
+    RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
+                                          getRRSIGWithRdataCount(7));
+    EXPECT_EQ(7, rdataset->getSigRdataCount());
+    RdataSet::destroy(mem_sgmt_, RRClass::IN(), rdataset);
+
+    // 8 would cause overflow in the normal 3-bit field if there were no extra
+    // count field.
+    rdataset = RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
+                                getRRSIGWithRdataCount(8));
+    EXPECT_EQ(8, rdataset->getSigRdataCount());
+    RdataSet::destroy(mem_sgmt_, RRClass::IN(), rdataset);
+
+    // Up to 2^16-1 RRSIGs are allowed (although that would be useless
+    // in practice)
+    rdataset = RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
+                                getRRSIGWithRdataCount(65535));
+    EXPECT_EQ(65535, rdataset->getSigRdataCount());
+    RdataSet::destroy(mem_sgmt_, RRClass::IN(), rdataset);
+
+    // Exceeding this limit will result in an exception.
+    EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
+                                  getRRSIGWithRdataCount(65536)),
+                 RdataSetError);
+    // To be very sure even try larger number than the threshold
+    EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
+                                  getRRSIGWithRdataCount(70000)),
+                 RdataSetError);
+}
+
+TEST_F(RdataSetTest, createWithRRSIGOnly) {
+    // A rare, but allowed, case: RdataSet without the main RRset but with
+    // RRSIG.
+    RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder_, ConstRRsetPtr(),
+                                          rrsig_rrset_);
+    checkRdataSet(*rdataset, false, true);
+    RdataSet::destroy(mem_sgmt_, RRClass::IN(), rdataset);
+}
+
+TEST_F(RdataSetTest, badCeate) {
+    // Neither the RRset nor RRSIG RRset is given
+    EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_, ConstRRsetPtr(),
+                                  ConstRRsetPtr()), isc::BadValue);
+
+    // Empty RRset (An RRset without RDATA)
+    ConstRRsetPtr empty_rrset(new RRset(Name("example.com"), RRClass::IN(),
+                                        RRType::A(), RRTTL(3600)));
+    EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_, empty_rrset,
+                                  ConstRRsetPtr()), isc::BadValue);
+    ConstRRsetPtr empty_rrsig(new RRset(Name("example.com"), RRClass::IN(),
+                                        RRType::RRSIG(), RRTTL(3600)));
+    EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_, ConstRRsetPtr(),
+                                  empty_rrsig), isc::BadValue);
+
+    // The RRset type and RRSIG's type covered don't match
+    ConstRRsetPtr bad_rrsig(textToRRset(
+                                "www.example.com. 1076895760 IN RRSIG "
+                                "NS 5 2 3600 20120814220826 20120715220826 "
+                                "1234 example.com. FAKE"));
+    EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_, a_rrset_, bad_rrsig),
+                 isc::BadValue);
+
+    // Pass non RRSIG for the sig parameter
+    EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_, a_rrset_, a_rrset_),
+                 isc::BadValue);
+
+    // Pass RRSIG for normal RRset (the RdataEncoder will catch this and throw)
+    EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_, rrsig_rrset_,
+                                  rrsig_rrset_),
+                 isc::BadValue);
+
+    // RR class doesn't match between RRset and RRSIG
+    ConstRRsetPtr badclass_rrsig(textToRRset(
+                                     "www.example.com. 1076895760 CH RRSIG "
+                                     "A 5 2 3600 20120814220826 "
+                                     "20120715220826 1234 example.com. FAKE",
+                                     RRClass::CH()));
+    EXPECT_THROW(RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
+                                  badclass_rrsig),
+                 isc::BadValue);
+}
+}
diff --git a/src/lib/datasrc/tests/memory/run_unittests.cc b/src/lib/datasrc/tests/memory/run_unittests.cc
new file mode 100644
index 0000000..6321976
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/run_unittests.cc
@@ -0,0 +1,26 @@
+// 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 <gtest/gtest.h>
+#include <util/unittests/run_all.h>
+#include <log/logger_support.h>
+
+int
+main(int argc, char* argv[]) {
+    ::testing::InitGoogleTest(&argc, argv);
+
+    isc::log::initLogger();
+
+    return (isc::util::unittests::run_all());
+}
diff --git a/src/lib/datasrc/tests/memory/segment_object_holder_unittest.cc b/src/lib/datasrc/tests/memory/segment_object_holder_unittest.cc
new file mode 100644
index 0000000..d27e364
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/segment_object_holder_unittest.cc
@@ -0,0 +1,67 @@
+// 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 <util/memory_segment_local.h>
+
+#include <datasrc/memory/segment_object_holder.h>
+
+#include <gtest/gtest.h>
+
+using namespace isc::util;
+using namespace isc::datasrc::memory;
+using namespace isc::datasrc::memory::detail;
+
+namespace {
+const int TEST_ARG_VAL = 42;    // arbitrary chosen magic number
+
+class TestObject {
+public:
+    static void destroy(MemorySegment& sgmt, TestObject* obj, int arg) {
+        sgmt.deallocate(obj, sizeof(*obj));
+        EXPECT_EQ(TEST_ARG_VAL, arg);
+    }
+};
+
+void
+useHolder(MemorySegment& sgmt, TestObject* obj, bool release) {
+    // Create a holder object, check the return value of get(), and,
+    // if requested, release the held object.  At the end of function
+    // the holder is destructed, and if the object hasn't been released by
+    // then, it should be deallocated.  Passed argument is checked in its
+    // deallocate().
+
+    typedef SegmentObjectHolder<TestObject, int> HolderType;
+    HolderType holder(sgmt, obj, TEST_ARG_VAL);
+    EXPECT_EQ(obj, holder.get());
+    if (release) {
+        EXPECT_EQ(obj, holder.release());
+    }
+}
+
+TEST(SegmentObjectHolderTest, foo) {
+    MemorySegmentLocal sgmt;
+    void* p = sgmt.allocate(sizeof(TestObject));
+    TestObject* obj = new(p) TestObject;
+
+    // Use holder, and release the content.  The memory shouldn't be
+    // deallocated.
+    useHolder(sgmt, obj, true);
+    EXPECT_FALSE(sgmt.allMemoryDeallocated());
+
+    // Use holder, and let it deallocate the object.  The memory segment
+    // should now be empty.
+    useHolder(sgmt, obj, false);
+    EXPECT_TRUE(sgmt.allMemoryDeallocated());
+}
+}
diff --git a/src/lib/datasrc/tests/memory/testdata/Makefile.am b/src/lib/datasrc/tests/memory/testdata/Makefile.am
new file mode 100644
index 0000000..dddbf0a
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/testdata/Makefile.am
@@ -0,0 +1,31 @@
+CLEANFILES = *.copied
+
+EXTRA_DIST =  empty.zone
+EXTRA_DIST += example.org.zone
+EXTRA_DIST += example.org-empty.zone
+
+EXTRA_DIST += example.org-broken1.zone
+EXTRA_DIST += example.org-broken2.zone
+EXTRA_DIST += example.org-cname-and-not-nsec-1.zone
+EXTRA_DIST += example.org-cname-and-not-nsec-2.zone
+EXTRA_DIST += example.org-dname-ns-apex-1.zone
+EXTRA_DIST += example.org-dname-ns-apex-2.zone
+EXTRA_DIST += example.org-dname-ns-nonapex-1.zone
+EXTRA_DIST += example.org-dname-ns-nonapex-2.zone
+EXTRA_DIST += example.org-duplicate-type-bad.zone
+EXTRA_DIST += example.org-duplicate-type.zone
+EXTRA_DIST += example.org-multiple-cname.zone
+EXTRA_DIST += example.org-multiple-dname.zone
+EXTRA_DIST += example.org-multiple-nsec3.zone
+EXTRA_DIST += example.org-multiple-nsec3param.zone
+EXTRA_DIST += example.org-multiple.zone
+EXTRA_DIST += example.org-nsec3-empty-salt.zone
+EXTRA_DIST += example.org-nsec3-fewer-labels.zone example.org-nsec3-more-labels.zone
+EXTRA_DIST += example.org-nsec3-signed-no-param.zone
+EXTRA_DIST += example.org-nsec3-signed.zone
+EXTRA_DIST += example.org-out-of-zone.zone
+EXTRA_DIST += example.org-rrsig-follows-nothing.zone
+EXTRA_DIST += example.org-rrsigs.zone
+EXTRA_DIST += example.org-wildcard-dname.zone
+EXTRA_DIST += example.org-wildcard-ns.zone
+EXTRA_DIST += example.org-wildcard-nsec3.zone
diff --git a/src/lib/datasrc/tests/memory/testdata/empty.zone b/src/lib/datasrc/tests/memory/testdata/empty.zone
new file mode 100644
index 0000000..e69de29
diff --git a/src/lib/datasrc/tests/memory/testdata/example.org-broken1.zone b/src/lib/datasrc/tests/memory/testdata/example.org-broken1.zone
new file mode 100644
index 0000000..317095d
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/testdata/example.org-broken1.zone
@@ -0,0 +1 @@
+This is a broken zone that should not parse.
diff --git a/src/lib/datasrc/tests/memory/testdata/example.org-broken2.zone b/src/lib/datasrc/tests/memory/testdata/example.org-broken2.zone
new file mode 100644
index 0000000..2f9fd98
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/testdata/example.org-broken2.zone
@@ -0,0 +1,5 @@
+;; broken example.org zone, where some RRs are OK, but others aren't
+example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 73 3600 300 3600000 3600
+ns1.example.org.		      3600 IN A		192.0.2.1
+ns2.example.org.		      3600 IN A		192.0.2.2
+ns2.a.example.com.		      3600 IN AAAA
diff --git a/src/lib/datasrc/tests/memory/testdata/example.org-cname-and-not-nsec-1.zone b/src/lib/datasrc/tests/memory/testdata/example.org-cname-and-not-nsec-1.zone
new file mode 100644
index 0000000..5533663
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/testdata/example.org-cname-and-not-nsec-1.zone
@@ -0,0 +1,4 @@
+;; CNAME + other is an error
+example.org.				      86400 IN SOA	ns.example.org. ns.example.org. 2012091009 7200 3600 2592000 1200
+a.example.org.				      7200  IN A	192.168.0.1
+a.example.org.				      3600  IN CNAME	foo.example.com.
diff --git a/src/lib/datasrc/tests/memory/testdata/example.org-cname-and-not-nsec-2.zone b/src/lib/datasrc/tests/memory/testdata/example.org-cname-and-not-nsec-2.zone
new file mode 100644
index 0000000..966aeeb
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/testdata/example.org-cname-and-not-nsec-2.zone
@@ -0,0 +1,4 @@
+;; CNAME + other is an error
+example.org.				      86400 IN SOA	ns.example.org. ns.example.org. 2012091007 7200 3600 2592000 1200
+a.example.org.				      3600  IN CNAME	foo.example.com.
+a.example.org.				      7200  IN A	192.168.0.1
diff --git a/src/lib/datasrc/tests/memory/testdata/example.org-dname-ns-apex-1.zone b/src/lib/datasrc/tests/memory/testdata/example.org-dname-ns-apex-1.zone
new file mode 100644
index 0000000..f57c25d
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/testdata/example.org-dname-ns-apex-1.zone
@@ -0,0 +1,4 @@
+;; DNAME + NS (apex)
+example.org.				      86400 IN SOA	ns.example.org. ns.example.org. 2012091015 7200 3600 2592000 1200
+example.org.				      3600  IN DNAME	foo.example.com.
+example.org.				      3600  IN NS	bar.example.com.
diff --git a/src/lib/datasrc/tests/memory/testdata/example.org-dname-ns-apex-2.zone b/src/lib/datasrc/tests/memory/testdata/example.org-dname-ns-apex-2.zone
new file mode 100644
index 0000000..bb3f191
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/testdata/example.org-dname-ns-apex-2.zone
@@ -0,0 +1,4 @@
+;; DNAME + NS (apex)
+example.org.				      86400 IN SOA	ns.example.org. ns.example.org. 2012091016 7200 3600 2592000 1200
+example.org.				      3600  IN NS	bar.example.com.
+example.org.				      3600  IN DNAME	foo.example.com.
diff --git a/src/lib/datasrc/tests/memory/testdata/example.org-dname-ns-nonapex-1.zone b/src/lib/datasrc/tests/memory/testdata/example.org-dname-ns-nonapex-1.zone
new file mode 100644
index 0000000..68a9805
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/testdata/example.org-dname-ns-nonapex-1.zone
@@ -0,0 +1,4 @@
+;; DNAME + NS (non-apex)
+example.org.				      86400 IN SOA	ns.example.org. ns.example.org. 2012091014 7200 3600 2592000 1200
+ns1.example.org.			      3600  IN DNAME	foo.example.com.
+ns1.example.org.			      3600  IN NS	bar.example.com.
diff --git a/src/lib/datasrc/tests/memory/testdata/example.org-dname-ns-nonapex-2.zone b/src/lib/datasrc/tests/memory/testdata/example.org-dname-ns-nonapex-2.zone
new file mode 100644
index 0000000..1b671dd
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/testdata/example.org-dname-ns-nonapex-2.zone
@@ -0,0 +1,4 @@
+;; DNAME + NS (non-apex)
+example.org.				      86400 IN SOA	ns.example.org. ns.example.org. 2012091015 7200 3600 2592000 1200
+ns1.example.org.			      3600  IN NS	bar.example.com.
+ns1.example.org.			      3600  IN DNAME	foo.example.com.
diff --git a/src/lib/datasrc/tests/memory/testdata/example.org-duplicate-type-bad.zone b/src/lib/datasrc/tests/memory/testdata/example.org-duplicate-type-bad.zone
new file mode 100644
index 0000000..06c7dff
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/testdata/example.org-duplicate-type-bad.zone
@@ -0,0 +1,4 @@
+example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 77 3600 300 3600000 3600
+ns1.example.org.		      3600 IN A	 	192.168.0.1
+ns1.example.org.		      3600 IN AAAA 	::1
+ns1.example.org.		      3600 IN A	 	192.168.0.2
diff --git a/src/lib/datasrc/tests/memory/testdata/example.org-duplicate-type.zone b/src/lib/datasrc/tests/memory/testdata/example.org-duplicate-type.zone
new file mode 100644
index 0000000..6e5c1b8
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/testdata/example.org-duplicate-type.zone
@@ -0,0 +1,4 @@
+example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 76 3600 300 3600000 3600
+ns1.example.org.		      3600 IN A	 	192.168.0.1
+ns1.example.org.		      3600 IN A	 	192.168.0.2
+ns1.example.org.		      3600 IN AAAA 	::1
diff --git a/src/lib/datasrc/tests/memory/testdata/example.org-empty.zone b/src/lib/datasrc/tests/memory/testdata/example.org-empty.zone
new file mode 100644
index 0000000..f11b9b8
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/testdata/example.org-empty.zone
@@ -0,0 +1,2 @@
+;; empty example.org zone
+example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 68 3600 300 3600000 3600
diff --git a/src/lib/datasrc/tests/memory/testdata/example.org-multiple-cname.zone b/src/lib/datasrc/tests/memory/testdata/example.org-multiple-cname.zone
new file mode 100644
index 0000000..0a0c983
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/testdata/example.org-multiple-cname.zone
@@ -0,0 +1,3 @@
+example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 78 3600 300 3600000 3600
+ns1.example.org.		      3600 IN CNAME	foo.example.com.
+ns1.example.org.		      3600 IN CNAME	bar.example.com.
diff --git a/src/lib/datasrc/tests/memory/testdata/example.org-multiple-dname.zone b/src/lib/datasrc/tests/memory/testdata/example.org-multiple-dname.zone
new file mode 100644
index 0000000..3d581d0
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/testdata/example.org-multiple-dname.zone
@@ -0,0 +1,3 @@
+example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 79 3600 300 3600000 3600
+ns1.example.org.		      3600 IN DNAME	foo.example.com.
+ns1.example.org.		      3600 IN DNAME	bar.example.com.
diff --git a/src/lib/datasrc/tests/memory/testdata/example.org-multiple-nsec3.zone b/src/lib/datasrc/tests/memory/testdata/example.org-multiple-nsec3.zone
new file mode 100644
index 0000000..874023a
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/testdata/example.org-multiple-nsec3.zone
@@ -0,0 +1,3 @@
+example.org.				      86400 IN SOA	ns.example.org. ns.example.org. 2012090702 7200 3600 2592000 1200
+09GM5T42SMIMT7R8DF6RTG80SFMS1NLU.example.org. 1200 IN NSEC3	1 0 10 AABBCCDD RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD A RRSIG
+09GM5T42SMIMT7R8DF6RTG80SFMS1NLU.example.org. 1200 IN NSEC3	1 0 10 AABBCCDD 09GM5T42SMIMT7R8DF6RTG80SFMS1NLU NS SOA RRSIG DNSKEY NSEC3PARAM
diff --git a/src/lib/datasrc/tests/memory/testdata/example.org-multiple-nsec3param.zone b/src/lib/datasrc/tests/memory/testdata/example.org-multiple-nsec3param.zone
new file mode 100644
index 0000000..5e69518
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/testdata/example.org-multiple-nsec3param.zone
@@ -0,0 +1,3 @@
+example.org.				      86400 IN SOA	ns.example.org. ns.example.org. 2012090700 7200 3600 2592000 1200
+example.org.				      0	IN NSEC3PARAM	1 0 10 AABBCCDD
+example.org.				      0	IN NSEC3PARAM	1 0 10 AABBCCDD
diff --git a/src/lib/datasrc/tests/memory/testdata/example.org-multiple.zone b/src/lib/datasrc/tests/memory/testdata/example.org-multiple.zone
new file mode 100644
index 0000000..f473ae6
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/testdata/example.org-multiple.zone
@@ -0,0 +1,4 @@
+;; Multiple RDATA for testing separate RRs iterator
+example.org.  		   	 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 78 3600 300 3600000 3600
+a.example.org.		   	 3600 IN A	192.168.0.1
+a.example.org.		   	 3600 IN A	192.168.0.2
diff --git a/src/lib/datasrc/tests/memory/testdata/example.org-nsec3-empty-salt.zone b/src/lib/datasrc/tests/memory/testdata/example.org-nsec3-empty-salt.zone
new file mode 100644
index 0000000..6c20ee9
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/testdata/example.org-nsec3-empty-salt.zone
@@ -0,0 +1,14 @@
+example.org.				      86400 IN SOA	ns.example.org. ns.example.org. 2012092602 7200 3600 2592000 1200
+example.org.				      86400 IN RRSIG	SOA 7 2 86400 20120301040838 20120131040838 19562 example.org. Jt9wCRLS5TQxZH0IBqrM9uMGD453rIoxYopfM9AjjRZfEx+HGlBpOZeR pGN7yLcN+URnicOD0ydLHiakaBODiZyNoYCKYG5d2ZOhL+026REnDKNM 0m5T3X3sczP+l55An/GITheTdrKt3Y1Ouc2yKI8ro8JjOxV/a4nGDWjK x9A=
+example.org.				      86400 IN NS	ns.example.org.
+example.org.				      86400 IN RRSIG	NS 7 2 86400 20120301040838 20120131040838 19562 example.org. gYXL3xK4IFdJU6TtiVuzqDBb2MeA8xB3AKtHlJGFTfTRNHyuej0ZGovx TeUYsLYmoiGYaJG66iD1tYYFq0qdj0xWq+LEa53ACtKvYf9IIwK4ijJs k0g6xCNavc6/qPppymDhN7MvoFVkW59uJa0HPWlsIIuRlEAr7xyt85vq yoA=
+example.org.				      86400 IN DNSKEY	256 3 7 AwEAAbrBkKf2gmGtG4aogZY4svIZCrOLLZlQzVHwz7WxJdTR8iEnvz/x Q/jReDroS5CBZWvzwLlhPIpsJAojx0oj0RvfJNsz3+6LN8q7x9u6+86B 85CYjTk3dcFOebgkF4fXr7/kkOX+ZY94Zk0Z1+pUC3eY4gkKcyME/Uxm O18PBTeB
+example.org.				      86400 IN RRSIG	DNSKEY 7 2 86400 20120301040838 20120131040838 19562 example.org. d0eLF8JqNHaGuBSX0ashU5c1O/wyWU43UUsKGrMQIoBDiJ588MWQOnas rwvW6vdkLNqRqCsP/B4epV/EtLL0tBsk5SHkTYbNo80gGrBufQ6YrWRr Ile8Z+h+MR4y9DybbjmuNKqaO4uQMg/X6+4HqRAKx1lmZMTcrcVeOwDM ZA4=
+example.org.				      0	IN NSEC3PARAM	1 0 10 -
+example.org.				      0	IN RRSIG	NSEC3PARAM 7 2 0 20120301040838 20120131040838 19562 example.org. Ggs5MiQDlXXt22Fz9DNg3Ujc0T6MBfumlRkd8/enBbJwLmqw2QXAzDEk pjUeGstCEHKzxJDJstavGoCpTDJgoV4Fd9szooMx69rzPrq9tdoM46jG xZHqw+Pv2fkRGC6aP7ZX1r3Qnpwpk47AQgATftbO4G6KcMcO8JoKE47x XLM=
+ns.example.org.				      86400 IN A	192.0.2.1
+ns.example.org.				      86400 IN RRSIG	A 7 3 86400 20120301040838 20120131040838 19562 example.org. dOH+Dxib8VcGnjLrKILsqDhS1wki6BWk1dZwpOGUGHyLWcLNW8ygWY2o r29jPhHtaFCNWpn46JebgnXDPRiQjaY3dQqL8rcf2QX1e3+Cicw1OSrs S0sUDE5DmMNEac+ZCUQ0quCStZTCldl05hlspV2RS92TpApnoOK0nXMp Uak=
+09GM5T42SMIMT7R8DF6RTG80SFMS1NLU.example.org. 1200 IN NSEC3	1 0 10 - RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD A RRSIG
+09GM5T42SMIMT7R8DF6RTG80SFMS1NLU.example.org. 1200 IN RRSIG	NSEC3 7 3 1200 20120301040838 20120131040838 19562 example.org. EdwMeepLf//lV+KpCAN+213Scv1rrZyj4i2OwoCP4XxxS3CWGSuvYuKO yfZc8wKRcrD/4YG6nZVXE0s5O8NahjBJmDIyVt4WkfZ6QthxGg8ggLVv cD3dFksPyiKHf/WrTOZPSsxvN5m/i1Ey6+YWS01Gf3WDCMWDauC7Nmh3 CTM=
+RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD.example.org. 1200 IN NSEC3	1 0 10 - 09GM5T42SMIMT7R8DF6RTG80SFMS1NLU NS SOA RRSIG DNSKEY NSEC3PARAM
+RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD.example.org. 1200 IN RRSIG	NSEC3 7 3 1200 20120301040838 20120131040838 19562 example.org. j7d8GL4YqX035FBcPPsEcSWHjWcKdlQMHLL4TB67xVNFnl4SEFQCp4OO AtPap5tkKakwgWxoQVN9XjnqrBz+oQhofDkB3aTatAjIIkcwcnrm3AYQ rTI3E03ySiRwuCPKVmHOLUV2cG6O4xzcmP+MYZcvPTS8V3F5LlaU22i7 A3E=
diff --git a/src/lib/datasrc/tests/memory/testdata/example.org-nsec3-fewer-labels.zone b/src/lib/datasrc/tests/memory/testdata/example.org-nsec3-fewer-labels.zone
new file mode 100644
index 0000000..0221269
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/testdata/example.org-nsec3-fewer-labels.zone
@@ -0,0 +1,3 @@
+;; NSEC3 names with labels != (origin_labels + 1)
+example.org.				      86400 IN SOA	ns.example.org. ns.example.org. 2012091001 7200 3600 2592000 1200
+example.org. 1200 IN NSEC3	1 0 10 AABBCCDD RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD A RRSIG
diff --git a/src/lib/datasrc/tests/memory/testdata/example.org-nsec3-more-labels.zone b/src/lib/datasrc/tests/memory/testdata/example.org-nsec3-more-labels.zone
new file mode 100644
index 0000000..efebcfb
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/testdata/example.org-nsec3-more-labels.zone
@@ -0,0 +1,3 @@
+;; NSEC3 names with labels != (origin_labels + 1)
+example.org.				      86400 IN SOA	ns.example.org. ns.example.org. 2012091002 7200 3600 2592000 1200
+a.b.example.org. 1200 IN NSEC3	1 0 10 AABBCCDD RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD A RRSIG
diff --git a/src/lib/datasrc/tests/memory/testdata/example.org-nsec3-signed-no-param.zone b/src/lib/datasrc/tests/memory/testdata/example.org-nsec3-signed-no-param.zone
new file mode 100644
index 0000000..5caa308
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/testdata/example.org-nsec3-signed-no-param.zone
@@ -0,0 +1,15 @@
+;; This file intentionally removes NSEC3PARAM from example.org.nsec3-signed
+example.org.				      86400 IN SOA	ns.example.org. ns.example.org. 2012013000 7200 3600 2592000 1200
+example.org.				      86400 IN RRSIG	SOA 7 2 86400 20120301040838 20120131040838 19562 example.org. Jt9wCRLS5TQxZH0IBqrM9uMGD453rIoxYopfM9AjjRZfEx+HGlBpOZeR pGN7yLcN+URnicOD0ydLHiakaBODiZyNoYCKYG5d2ZOhL+026REnDKNM 0m5T3X3sczP+l55An/GITheTdrKt3Y1Ouc2yKI8ro8JjOxV/a4nGDWjK x9A=
+example.org.				      86400 IN NS	ns.example.org.
+example.org.				      86400 IN RRSIG	NS 7 2 86400 20120301040838 20120131040838 19562 example.org. gYXL3xK4IFdJU6TtiVuzqDBb2MeA8xB3AKtHlJGFTfTRNHyuej0ZGovx TeUYsLYmoiGYaJG66iD1tYYFq0qdj0xWq+LEa53ACtKvYf9IIwK4ijJs k0g6xCNavc6/qPppymDhN7MvoFVkW59uJa0HPWlsIIuRlEAr7xyt85vq yoA=
+example.org.				      86400 IN DNSKEY	256 3 7 AwEAAbrBkKf2gmGtG4aogZY4svIZCrOLLZlQzVHwz7WxJdTR8iEnvz/x Q/jReDroS5CBZWvzwLlhPIpsJAojx0oj0RvfJNsz3+6LN8q7x9u6+86B 85CYjTk3dcFOebgkF4fXr7/kkOX+ZY94Zk0Z1+pUC3eY4gkKcyME/Uxm O18PBTeB
+example.org.				      86400 IN RRSIG	DNSKEY 7 2 86400 20120301040838 20120131040838 19562 example.org. d0eLF8JqNHaGuBSX0ashU5c1O/wyWU43UUsKGrMQIoBDiJ588MWQOnas rwvW6vdkLNqRqCsP/B4epV/EtLL0tBsk5SHkTYbNo80gGrBufQ6YrWRr Ile8Z+h+MR4y9DybbjmuNKqaO4uQMg/X6+4HqRAKx1lmZMTcrcVeOwDM ZA4=
+;; example.org.				      0	IN NSEC3PARAM	1 0 10 AABBCCDD
+;; example.org.				      0	IN RRSIG	NSEC3PARAM 7 2 0 20120301040838 20120131040838 19562 example.org. Ggs5MiQDlXXt22Fz9DNg3Ujc0T6MBfumlRkd8/enBbJwLmqw2QXAzDEk pjUeGstCEHKzxJDJstavGoCpTDJgoV4Fd9szooMx69rzPrq9tdoM46jG xZHqw+Pv2fkRGC6aP7ZX1r3Qnpwpk47AQgATftbO4G6KcMcO8JoKE47x XLM=
+ns.example.org.				      86400 IN A	192.0.2.1
+ns.example.org.				      86400 IN RRSIG	A 7 3 86400 20120301040838 20120131040838 19562 example.org. dOH+Dxib8VcGnjLrKILsqDhS1wki6BWk1dZwpOGUGHyLWcLNW8ygWY2o r29jPhHtaFCNWpn46JebgnXDPRiQjaY3dQqL8rcf2QX1e3+Cicw1OSrs S0sUDE5DmMNEac+ZCUQ0quCStZTCldl05hlspV2RS92TpApnoOK0nXMp Uak=
+09GM5T42SMIMT7R8DF6RTG80SFMS1NLU.example.org. 1200 IN NSEC3	1 0 10 AABBCCDD RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD A RRSIG
+09GM5T42SMIMT7R8DF6RTG80SFMS1NLU.example.org. 1200 IN RRSIG	NSEC3 7 3 1200 20120301040838 20120131040838 19562 example.org. EdwMeepLf//lV+KpCAN+213Scv1rrZyj4i2OwoCP4XxxS3CWGSuvYuKO yfZc8wKRcrD/4YG6nZVXE0s5O8NahjBJmDIyVt4WkfZ6QthxGg8ggLVv cD3dFksPyiKHf/WrTOZPSsxvN5m/i1Ey6+YWS01Gf3WDCMWDauC7Nmh3 CTM=
+RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD.example.org. 1200 IN NSEC3	1 0 10 AABBCCDD 09GM5T42SMIMT7R8DF6RTG80SFMS1NLU NS SOA RRSIG DNSKEY NSEC3PARAM
+RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD.example.org. 1200 IN RRSIG	NSEC3 7 3 1200 20120301040838 20120131040838 19562 example.org. j7d8GL4YqX035FBcPPsEcSWHjWcKdlQMHLL4TB67xVNFnl4SEFQCp4OO AtPap5tkKakwgWxoQVN9XjnqrBz+oQhofDkB3aTatAjIIkcwcnrm3AYQ rTI3E03ySiRwuCPKVmHOLUV2cG6O4xzcmP+MYZcvPTS8V3F5LlaU22i7 A3E=
diff --git a/src/lib/datasrc/tests/memory/testdata/example.org-nsec3-signed.zone b/src/lib/datasrc/tests/memory/testdata/example.org-nsec3-signed.zone
new file mode 100644
index 0000000..9c1195f
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/testdata/example.org-nsec3-signed.zone
@@ -0,0 +1,14 @@
+example.org.				      86400 IN SOA	ns.example.org. ns.example.org. 2012013000 7200 3600 2592000 1200
+example.org.				      86400 IN RRSIG	SOA 7 2 86400 20120301040838 20120131040838 19562 example.org. Jt9wCRLS5TQxZH0IBqrM9uMGD453rIoxYopfM9AjjRZfEx+HGlBpOZeR pGN7yLcN+URnicOD0ydLHiakaBODiZyNoYCKYG5d2ZOhL+026REnDKNM 0m5T3X3sczP+l55An/GITheTdrKt3Y1Ouc2yKI8ro8JjOxV/a4nGDWjK x9A=
+example.org.				      86400 IN NS	ns.example.org.
+example.org.				      86400 IN RRSIG	NS 7 2 86400 20120301040838 20120131040838 19562 example.org. gYXL3xK4IFdJU6TtiVuzqDBb2MeA8xB3AKtHlJGFTfTRNHyuej0ZGovx TeUYsLYmoiGYaJG66iD1tYYFq0qdj0xWq+LEa53ACtKvYf9IIwK4ijJs k0g6xCNavc6/qPppymDhN7MvoFVkW59uJa0HPWlsIIuRlEAr7xyt85vq yoA=
+example.org.				      86400 IN DNSKEY	256 3 7 AwEAAbrBkKf2gmGtG4aogZY4svIZCrOLLZlQzVHwz7WxJdTR8iEnvz/x Q/jReDroS5CBZWvzwLlhPIpsJAojx0oj0RvfJNsz3+6LN8q7x9u6+86B 85CYjTk3dcFOebgkF4fXr7/kkOX+ZY94Zk0Z1+pUC3eY4gkKcyME/Uxm O18PBTeB
+example.org.				      86400 IN RRSIG	DNSKEY 7 2 86400 20120301040838 20120131040838 19562 example.org. d0eLF8JqNHaGuBSX0ashU5c1O/wyWU43UUsKGrMQIoBDiJ588MWQOnas rwvW6vdkLNqRqCsP/B4epV/EtLL0tBsk5SHkTYbNo80gGrBufQ6YrWRr Ile8Z+h+MR4y9DybbjmuNKqaO4uQMg/X6+4HqRAKx1lmZMTcrcVeOwDM ZA4=
+example.org.				      0	IN NSEC3PARAM	1 0 10 AABBCCDD
+example.org.				      0	IN RRSIG	NSEC3PARAM 7 2 0 20120301040838 20120131040838 19562 example.org. Ggs5MiQDlXXt22Fz9DNg3Ujc0T6MBfumlRkd8/enBbJwLmqw2QXAzDEk pjUeGstCEHKzxJDJstavGoCpTDJgoV4Fd9szooMx69rzPrq9tdoM46jG xZHqw+Pv2fkRGC6aP7ZX1r3Qnpwpk47AQgATftbO4G6KcMcO8JoKE47x XLM=
+ns.example.org.				      86400 IN A	192.0.2.1
+ns.example.org.				      86400 IN RRSIG	A 7 3 86400 20120301040838 20120131040838 19562 example.org. dOH+Dxib8VcGnjLrKILsqDhS1wki6BWk1dZwpOGUGHyLWcLNW8ygWY2o r29jPhHtaFCNWpn46JebgnXDPRiQjaY3dQqL8rcf2QX1e3+Cicw1OSrs S0sUDE5DmMNEac+ZCUQ0quCStZTCldl05hlspV2RS92TpApnoOK0nXMp Uak=
+09GM5T42SMIMT7R8DF6RTG80SFMS1NLU.example.org. 1200 IN NSEC3	1 0 10 AABBCCDD RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD A RRSIG
+09GM5T42SMIMT7R8DF6RTG80SFMS1NLU.example.org. 1200 IN RRSIG	NSEC3 7 3 1200 20120301040838 20120131040838 19562 example.org. EdwMeepLf//lV+KpCAN+213Scv1rrZyj4i2OwoCP4XxxS3CWGSuvYuKO yfZc8wKRcrD/4YG6nZVXE0s5O8NahjBJmDIyVt4WkfZ6QthxGg8ggLVv cD3dFksPyiKHf/WrTOZPSsxvN5m/i1Ey6+YWS01Gf3WDCMWDauC7Nmh3 CTM=
+RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD.example.org. 1200 IN NSEC3	1 0 10 AABBCCDD 09GM5T42SMIMT7R8DF6RTG80SFMS1NLU NS SOA RRSIG DNSKEY NSEC3PARAM
+RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD.example.org. 1200 IN RRSIG	NSEC3 7 3 1200 20120301040838 20120131040838 19562 example.org. j7d8GL4YqX035FBcPPsEcSWHjWcKdlQMHLL4TB67xVNFnl4SEFQCp4OO AtPap5tkKakwgWxoQVN9XjnqrBz+oQhofDkB3aTatAjIIkcwcnrm3AYQ rTI3E03ySiRwuCPKVmHOLUV2cG6O4xzcmP+MYZcvPTS8V3F5LlaU22i7 A3E=
diff --git a/src/lib/datasrc/tests/memory/testdata/example.org-out-of-zone.zone b/src/lib/datasrc/tests/memory/testdata/example.org-out-of-zone.zone
new file mode 100644
index 0000000..e3afb74
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/testdata/example.org-out-of-zone.zone
@@ -0,0 +1,5 @@
+;; test zone file used for ZoneFinderContext tests.
+;; RRSIGs are (obviouslly) faked ones for testing.
+
+example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 75 3600 300 3600000 3600
+a.example.com.	  		      3600 IN A	 	192.168.0.1
diff --git a/src/lib/datasrc/tests/memory/testdata/example.org-rrsig-follows-nothing.zone b/src/lib/datasrc/tests/memory/testdata/example.org-rrsig-follows-nothing.zone
new file mode 100644
index 0000000..ef5f887
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/testdata/example.org-rrsig-follows-nothing.zone
@@ -0,0 +1,5 @@
+;; test zone file used for ZoneFinderContext tests.
+;; RRSIGs are (obviouslly) faked ones for testing.
+
+example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 68 3600 300 3600000 3600
+ns1.example.org.		      3600 IN RRSIG	A 7 3 3600 20150420235959 20051021000000 40430 example.org. FAKEFAKE
diff --git a/src/lib/datasrc/tests/memory/testdata/example.org-rrsigs.zone b/src/lib/datasrc/tests/memory/testdata/example.org-rrsigs.zone
new file mode 100644
index 0000000..1c780b1
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/testdata/example.org-rrsigs.zone
@@ -0,0 +1,8 @@
+;; test zone file used for ZoneFinderContext tests.
+;; RRSIGs are (obviouslly) faked ones for testing.
+
+example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 74 3600 300 3600000 3600
+ns1.example.org.		      3600 IN A	 	192.168.0.1
+ns1.example.org.		      3600 IN RRSIG	A 7 3 3600 20150420235959 20051021000000 40430 example.org. FAKEFAKE
+ns1.example.org.		      3600 IN RRSIG	A 7 2 3600 20150420235959 20051021000000 40430 example.org. FAKEFAKE
+ns1.example.org.		      3600 IN AAAA 	::1
diff --git a/src/lib/datasrc/tests/memory/testdata/example.org-wildcard-dname.zone b/src/lib/datasrc/tests/memory/testdata/example.org-wildcard-dname.zone
new file mode 100644
index 0000000..0d03b0d
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/testdata/example.org-wildcard-dname.zone
@@ -0,0 +1,4 @@
+;; test zone file with wildcard DNAME names
+
+example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 79 3600 300 3600000 3600
+*.example.org. 3600 IN DNAME dname.example.com.
diff --git a/src/lib/datasrc/tests/memory/testdata/example.org-wildcard-ns.zone b/src/lib/datasrc/tests/memory/testdata/example.org-wildcard-ns.zone
new file mode 100644
index 0000000..2933515
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/testdata/example.org-wildcard-ns.zone
@@ -0,0 +1,4 @@
+;; test zone file with wildcard NS names
+
+example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 78 3600 300 3600000 3600
+*.example.org.			      3600 IN NS	ns1.example.org.
diff --git a/src/lib/datasrc/tests/memory/testdata/example.org-wildcard-nsec3.zone b/src/lib/datasrc/tests/memory/testdata/example.org-wildcard-nsec3.zone
new file mode 100644
index 0000000..feee116
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/testdata/example.org-wildcard-nsec3.zone
@@ -0,0 +1,4 @@
+;; test zone file with wildcard NS names
+
+example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 79 3600 300 3600000 3600
+*.example.org. 1200 IN NSEC3	1 0 10 AABBCCDD RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD A RRSIG
diff --git a/src/lib/datasrc/tests/memory/testdata/example.org.zone b/src/lib/datasrc/tests/memory/testdata/example.org.zone
new file mode 100644
index 0000000..e499e0d
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/testdata/example.org.zone
@@ -0,0 +1,81 @@
+;; test zone file used for ZoneFinderContext tests.
+;; RRSIGs are (obviouslly) faked ones for testing.
+
+example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 67 3600 300 3600000 3600
+example.org.			      3600 IN NS	ns1.example.org.
+example.org.			      3600 IN NS	ns2.example.org.
+example.org.			      3600 IN MX	1 mx1.example.org.
+example.org.			      3600 IN MX	2 mx2.example.org.
+example.org.			      3600 IN MX	3 mx.a.example.org.
+
+ns1.example.org.		      3600 IN A		192.0.2.1
+ns1.example.org.		      3600 IN RRSIG	A 7 3 3600 20150420235959 20051021000000 40430 example.org. FAKEFAKE
+ns1.example.org.		      3600 IN AAAA	2001:db8::1
+ns1.example.org.		      3600 IN RRSIG	AAAA 7 3 3600 20150420235959 20051021000000 40430 example.org. FAKEFAKEFAKE
+ns2.example.org.		      3600 IN A		192.0.2.2
+ns2.example.org.		      3600 IN TXT	"text data"
+
+mx1.example.org.		      3600 IN A		192.0.2.10
+mx2.example.org.		      3600 IN AAAA	2001:db8::10
+
+;; delegation
+a.example.org.			      3600 IN NS	ns1.a.example.org.
+a.example.org.			      3600 IN NS	ns2.a.example.org.
+a.example.org.			      3600 IN NS	ns.example.com.
+
+ns1.a.example.org.		      3600 IN A		192.0.2.5
+ns2.a.example.org.		      3600 IN A		192.0.2.6
+ns2.a.example.org.		      3600 IN AAAA	2001:db8::6
+mx.a.example.org.		      3600 IN A		192.0.2.7
+
+;; delegation, one of its NS names is at zone cut.
+b.example.org.			      3600 IN NS	ns.b.example.org.
+b.example.org.			      3600 IN NS	b.example.org.
+b.example.org.			      3600 IN AAAA	2001:db8::8
+
+ns.b.example.org.		      3600 IN A		192.0.2.9
+
+;; The MX name is at a zone cut.  shouldn't be included in the
+;; additional section.
+mxatcut.example.org.		      3600 IN MX	1 b.example.org.
+
+;; delegation, one of its NS names is under a DNAME delegation point;
+;; another is at that point; and yet another is under DNAME below a
+;; zone cut.
+c.example.org. 	      	      3600 IN NS	ns.dname.example.org.
+c.example.org. 	      	      3600 IN NS	dname.example.org.
+c.example.org.      	      3600 IN NS	ns.deepdname.example.org.
+ns.dname.example.org.		      3600 IN A		192.0.2.11
+dname.example.org.		      3600 IN A		192.0.2.12
+ns.deepdname.example.org.	      3600 IN AAAA	2001:db8::9
+
+;; delegation, one of its NS name is at an empty non terminal.
+d.example.org. 	      	      3600 IN NS	ns.empty.example.org.
+d.example.org. 	      	      3600 IN NS	ns1.example.org.
+;; by adding these two we can create an empty RB node for
+;; ns.empty.example.org in the in-memory zone
+foo.ns.empty.example.org.     3600 IN A		192.0.2.13
+bar.ns.empty.example.org.     3600 IN A		192.0.2.14
+
+;; delegation; the NS name matches a wildcard (and there's no exact
+;; match).  One of the NS names matches an empty wildcard node, for
+;; which no additional record should be provided (or any other
+;; disruption should happen).
+e.example.org. 	      	      3600 IN NS	ns.wild.example.org.
+e.example.org. 	      	      3600 IN NS	ns.emptywild.example.org.
+e.example.org. 	      	      3600 IN NS	ns2.example.org.
+*.wild.example.org.	      3600 IN A		192.0.2.15
+a.*.emptywild.example.org.    3600 IN AAAA	2001:db8::2
+
+;; additional for an answer RRset (MX) as a result of wildcard
+;; expansion
+*.wildmx.example.org. 3600 IN MX 1 mx1.example.org.
+
+;; CNAME
+alias.example.org. 3600 IN CNAME cname.example.org.
+
+;; DNAME
+dname.example.org. 3600 IN DNAME dname.example.com.
+
+;; DNAME under a NS (strange one)
+deepdname.c.example.org. 3600 IN DNAME deepdname.example.com.
diff --git a/src/lib/datasrc/tests/memory/treenode_rrset_unittest.cc b/src/lib/datasrc/tests/memory/treenode_rrset_unittest.cc
new file mode 100644
index 0000000..02ad2bd
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/treenode_rrset_unittest.cc
@@ -0,0 +1,631 @@
+// 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 <util/buffer.h>
+#include <util/memory_segment_local.h>
+
+#include <datasrc/memory/treenode_rrset.h>
+#include <datasrc/memory/rdataset.h>
+#include <datasrc/memory/rdata_serialization.h>
+#include <datasrc/memory/zone_data.h>
+
+#include <util/unittests/wiredata.h>
+#include <testutils/dnsmessage_test.h>
+
+#include <gtest/gtest.h>
+
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <string>
+#include <vector>
+
+using std::vector;
+using std::string;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+using namespace isc::datasrc::memory;
+using namespace isc::testutils;
+using isc::util::unittests::matchWireData;
+using isc::util::OutputBuffer;
+
+namespace {
+
+class TreeNodeRRsetTest : public ::testing::Test {
+protected:
+    TreeNodeRRsetTest() :
+        rrclass_(RRClass::IN()),
+        origin_name_("example.com"), www_name_("www.example.com"),
+        wildcard_name_("*.example.com"), match_name_("match.example.com"),
+        ns_rrset_(textToRRset("example.com. 3600 IN NS ns.example.com.")),
+        a_rrset_(textToRRset("www.example.com. 3600 IN A 192.0.2.1\n"
+                             "www.example.com. 3600 IN A 192.0.2.2")),
+        aaaa_rrset_(textToRRset("www.example.com. 3600 IN AAAA "
+                                "2001:db8::1\n")),
+        dname_rrset_(textToRRset("example.com. 3600 IN DNAME d.example.org.")),
+        a_rrsig_rrset_(textToRRset("www.example.com. 3600 IN RRSIG "
+                                   "A 5 2 3600 20120814220826 20120715220826 "
+                                   "1234 example.com. FAKE")),
+        aaaa_rrsig_rrset_(textToRRset("www.example.com. 3600 IN RRSIG AAAA 5 2"
+                                      " 3600 20120814220826 20120715220826 "
+                                      "1234 example.com. FAKE\n"
+                                      "www.example.com. 3600 IN RRSIG AAAA 5 2"
+                                      " 3600 20120814220826 20120715220826 "
+                                      "4321 example.com. FAKE\n")),
+        txt_rrsig_rrset_(textToRRset("www.example.com. 3600 IN RRSIG TXT 5 2"
+                                     " 3600 20120814220826 20120715220826 "
+                                     "1234 example.com. FAKE\n")),
+        wildmatch_rrset_(textToRRset(
+                             "match.example.com. 3600 IN A 192.0.2.1\n"
+                             "match.example.com. 3600 IN A 192.0.2.2")),
+        wildmatch_rrsig_rrset_(textToRRset(
+                                   "match.example.com. 3600 IN RRSIG "
+                                   "A 5 2 3600 20120814220826 20120715220826 "
+                                   "1234 example.com. FAKE")),
+        zone_data_(NULL), origin_node_(NULL), www_node_(NULL),
+        wildcard_node_(NULL), ns_rdataset_(NULL), dname_rdataset_(NULL),
+        a_rdataset_(NULL), aaaa_rdataset_(NULL), rrsig_only_rdataset_(NULL),
+        wildcard_rdataset_(NULL)
+    {}
+    void SetUp() {
+        // We create some common test data here in SetUp() so it will be
+        // as exception safe as possible.
+
+        zone_data_ = ZoneData::create(mem_sgmt_, origin_name_);
+
+        zone_data_->insertName(mem_sgmt_, origin_name_, &origin_node_);
+        ns_rdataset_ = RdataSet::create(mem_sgmt_, encoder_, ns_rrset_,
+                                        ConstRRsetPtr());
+        origin_node_->setData(ns_rdataset_);
+        dname_rdataset_ = RdataSet::create(mem_sgmt_, encoder_, dname_rrset_,
+                                           ConstRRsetPtr());
+        ns_rdataset_->next = dname_rdataset_;
+
+        zone_data_->insertName(mem_sgmt_, www_name_, &www_node_);
+        a_rdataset_ = RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
+                                       a_rrsig_rrset_);
+        www_node_->setData(a_rdataset_);
+
+        aaaa_rdataset_ = RdataSet::create(mem_sgmt_, encoder_, aaaa_rrset_,
+                                          aaaa_rrsig_rrset_);
+        a_rdataset_->next = aaaa_rdataset_;
+
+        // A rare (half broken) case of RRSIG-only set
+        rrsig_only_rdataset_ = RdataSet::create(mem_sgmt_, encoder_,
+                                                ConstRRsetPtr(),
+                                                txt_rrsig_rrset_);
+        aaaa_rdataset_->next = rrsig_only_rdataset_;
+
+        zone_data_->insertName(mem_sgmt_, wildcard_name_, &wildcard_node_);
+        wildcard_rdataset_ = RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
+                                              a_rrsig_rrset_);
+        wildcard_node_->setData(wildcard_rdataset_);
+    }
+    void TearDown() {
+        ZoneData::destroy(mem_sgmt_, zone_data_, rrclass_);
+        // detect any memory leak
+        EXPECT_TRUE(mem_sgmt_.allMemoryDeallocated());
+    }
+
+    const RRClass rrclass_;
+    const Name origin_name_, www_name_, wildcard_name_, match_name_;
+    isc::util::MemorySegmentLocal mem_sgmt_;
+    RdataEncoder encoder_;
+    MessageRenderer renderer_, renderer_expected_;
+    ConstRRsetPtr ns_rrset_, a_rrset_, aaaa_rrset_, dname_rrset_,
+        a_rrsig_rrset_, aaaa_rrsig_rrset_, txt_rrsig_rrset_,
+        wildmatch_rrset_, wildmatch_rrsig_rrset_;
+    ZoneData* zone_data_;
+    ZoneNode* origin_node_;
+    ZoneNode* www_node_;
+    ZoneNode* wildcard_node_;
+    RdataSet* ns_rdataset_;
+    RdataSet* dname_rdataset_;
+    RdataSet* a_rdataset_;
+    RdataSet* aaaa_rdataset_;
+    RdataSet* rrsig_only_rdataset_;
+    RdataSet* wildcard_rdataset_; // for wildcard (type doesn't matter much)
+};
+
+void
+compareRRSIGData(RdataIteratorPtr rit, const void* data, size_t data_len) {
+    ASSERT_FALSE(rit->isLast());
+
+    OutputBuffer buffer(0);
+    rit->getCurrent().toWire(buffer);
+    matchWireData(data, data_len, buffer.getData(), buffer.getLength());
+    rit->next();
+}
+
+// Check some trivial fields of a constructed TreeNodeRRset (passed as
+// AbstractRRset as we'd normally use it in polymorphic way).
+// Other complicated fields are checked through rendering tests.
+void
+checkBasicFields(const AbstractRRset& actual_rrset, const RdataSet* rdataset,
+                 const Name& expected_name,
+                 const RRClass& expected_class, const RRType& expected_type,
+                 const uint32_t expected_ttl,
+                 size_t expected_rdatacount, size_t expected_sigcount)
+{
+    EXPECT_EQ(expected_name, actual_rrset.getName());
+    EXPECT_EQ(expected_class, actual_rrset.getClass());
+    EXPECT_EQ(expected_type, actual_rrset.getType());
+    EXPECT_EQ(RRTTL(expected_ttl), actual_rrset.getTTL());
+    EXPECT_EQ(expected_rdatacount, actual_rrset.getRdataCount());
+    EXPECT_EQ(expected_sigcount, actual_rrset.getRRsigDataCount());
+
+    // getRRsig() should return non NULL iff the RRset is expected to be signed
+    if (expected_sigcount == 0) {
+        EXPECT_FALSE(actual_rrset.getRRsig());
+    } else {
+        ConstRRsetPtr actual_sigrrset = actual_rrset.getRRsig();
+        ASSERT_TRUE(actual_sigrrset);
+        EXPECT_EQ(expected_name, actual_sigrrset->getName());
+        EXPECT_EQ(expected_class, actual_sigrrset->getClass());
+        EXPECT_EQ(RRType::RRSIG(), actual_sigrrset->getType());
+        EXPECT_EQ(RRTTL(expected_ttl), actual_sigrrset->getTTL());
+        EXPECT_EQ(expected_sigcount, actual_sigrrset->getRdataCount());
+
+        // Compare each RRSIG RDATA
+        RdataIteratorPtr rit = actual_sigrrset->getRdataIterator();
+        RdataReader reader(expected_class, expected_type,
+                           rdataset->getDataBuf(), expected_rdatacount,
+                           expected_sigcount, &RdataReader::emptyNameAction,
+                           boost::bind(compareRRSIGData, rit, _1, _2));
+        while (reader.nextSig() != RdataReader::RRSET_BOUNDARY) {}
+        EXPECT_TRUE(rit->isLast()); // should check all RDATAs
+    }
+}
+
+// The following two are trivial wrapper to create a shared pointer
+// version of TreeNodeRRset object in order to work around dubious
+// behavior of some C++ compiler: they reject getting a const reference to
+// a temporary non-copyable object.
+boost::shared_ptr<TreeNodeRRset>
+createRRset(const RRClass& rrclass, const ZoneNode* node,
+            const RdataSet* rdataset, bool dnssec_ok)
+{
+    return (boost::shared_ptr<TreeNodeRRset>(
+                new TreeNodeRRset(rrclass, node, rdataset, dnssec_ok)));
+}
+
+boost::shared_ptr<TreeNodeRRset>
+createRRset(const Name& realname, const RRClass& rrclass, const ZoneNode* node,
+            const RdataSet* rdataset, bool dnssec_ok)
+{
+    return (boost::shared_ptr<TreeNodeRRset>(
+                new TreeNodeRRset(realname, rrclass, node, rdataset,
+                                  dnssec_ok)));
+}
+
+TEST_F(TreeNodeRRsetTest, create) {
+    // Constructed with RRSIG, and it should be visible.
+    checkBasicFields(*createRRset(rrclass_, www_node_, a_rdataset_, true),
+                     a_rdataset_, www_name_, rrclass_, RRType::A(), 3600, 2,
+                     1);
+    // Constructed with RRSIG, and it should be invisible.
+    checkBasicFields(*createRRset(rrclass_, www_node_, a_rdataset_, false),
+                     a_rdataset_, www_name_, rrclass_, RRType::A(), 3600, 2,
+                     0);
+    // Constructed without RRSIG, and it would be visible (but of course won't)
+    checkBasicFields(*createRRset(rrclass_, origin_node_, ns_rdataset_, true),
+                     ns_rdataset_, origin_name_, rrclass_, RRType::NS(), 3600,
+                     1, 0);
+    // Constructed without RRSIG, and it should be visible
+    checkBasicFields(*createRRset(rrclass_, origin_node_, ns_rdataset_, false),
+                     ns_rdataset_, origin_name_, rrclass_, RRType::NS(), 3600,
+                     1, 0);
+    // RRSIG-only case (note the RRset's type is covered type)
+    checkBasicFields(*createRRset(rrclass_, www_node_, rrsig_only_rdataset_,
+                                  true),
+                     rrsig_only_rdataset_, www_name_, rrclass_, RRType::TXT(),
+                     3600, 0, 1);
+    // RRSIG-only case (note the RRset's type is covered type), but it's
+    // invisible
+    checkBasicFields(*createRRset(rrclass_, www_node_, rrsig_only_rdataset_,
+                                  false),
+                     rrsig_only_rdataset_, www_name_, rrclass_, RRType::TXT(),
+                     3600, 0, 0);
+    // Wildcard substitution
+    checkBasicFields(*createRRset(match_name_, rrclass_,
+                                  wildcard_node_, wildcard_rdataset_,
+                                  true),
+                     wildcard_rdataset_, match_name_, rrclass_, RRType::A(),
+                     3600, 2, 1);
+}
+
+// The following two templated functions are helper to encapsulate the
+// concept truncation and handle MessageRenderer and OutputBuffer transparently
+// in templated test cases.
+template <typename OutputType>
+void
+setOutputLengthLimit(OutputType& output, size_t len_limit) {
+    output.setLengthLimit(len_limit);
+}
+template <>
+void
+setOutputLengthLimit<OutputBuffer>(OutputBuffer&, size_t) {
+}
+
+template <typename OutputType>
+bool
+isOutputTruncated(OutputType& output) {
+    return (output.isTruncated());
+}
+template <>
+bool
+isOutputTruncated<OutputBuffer>(OutputBuffer&) {
+    return (false);
+}
+
+// Templated so we so can support OutputBuffer version of toWire().
+// We use the above helper templated functions for some renderer only methods.
+// We test two sets of cases: normal rendering case and case when truncation
+// is expected.  The latter is effectively for MessageRenderer only.
+// If len_limit == 0, we consider it the normal case; otherwise it's for
+// truncation.  prepended_name isn't used for the truncation case.
+template <typename OutputType>
+void
+checkToWireResult(OutputType& expected_output, OutputType& actual_output,
+                  const AbstractRRset& actual_rrset,
+                  const Name& prepended_name,
+                  ConstRRsetPtr rrset, ConstRRsetPtr rrsig_rrset,
+                  bool dnssec_ok,
+                  size_t len_limit = 0,
+                  size_t expected_result = 0)
+{
+    expected_output.clear();
+    actual_output.clear();
+
+    if (len_limit == 0) {       // normal rendering
+        // Prepare "actual" rendered data.  We prepend a name to confirm the
+        // owner name should be compressed in both cases.
+        prepended_name.toWire(actual_output);
+        const size_t rdata_count = rrset ? rrset->getRdataCount() : 0;
+        const int expected_ret = (dnssec_ok && rrsig_rrset) ?
+            rdata_count + rrsig_rrset->getRdataCount() : rdata_count;
+        EXPECT_EQ(expected_ret, actual_rrset.toWire(actual_output));
+    } else {                    // truncation
+        setOutputLengthLimit(actual_output, len_limit);
+        EXPECT_EQ(expected_result, actual_rrset.toWire(actual_output));
+        EXPECT_TRUE(isOutputTruncated(actual_output)); // always true here
+    }
+
+    // Prepare "expected" data.
+    if (len_limit == 0) {       // normal rendering
+        prepended_name.toWire(expected_output);
+    } else {                    // truncation
+        setOutputLengthLimit(expected_output, len_limit);
+    }
+    if (rrset) {
+        rrset->toWire(expected_output);
+    }
+    if (!isOutputTruncated(expected_output) && dnssec_ok && rrsig_rrset) {
+        rrsig_rrset->toWire(expected_output);
+    }
+
+    // Compare the two.
+    matchWireData(expected_output.getData(), expected_output.getLength(),
+                  actual_output.getData(), actual_output.getLength());
+}
+
+TEST_F(TreeNodeRRsetTest, toWire) {
+    MessageRenderer expected_renderer, actual_renderer;
+    OutputBuffer expected_buffer(0), actual_buffer(0);
+
+    {
+        SCOPED_TRACE("with RRSIG, DNSSEC OK");
+        const TreeNodeRRset rrset(rrclass_, www_node_, a_rdataset_, true);
+        checkToWireResult(expected_renderer, actual_renderer, rrset,
+                          www_name_, a_rrset_, a_rrsig_rrset_, true);
+        // Currently the buffer version throws
+        EXPECT_THROW(
+            checkToWireResult(expected_buffer, actual_buffer, rrset,
+                              www_name_, a_rrset_, a_rrsig_rrset_, true),
+            isc::Unexpected);
+    }
+
+    {
+        SCOPED_TRACE("with RRSIG, DNSSEC not OK");
+        const TreeNodeRRset rrset(rrclass_, www_node_, a_rdataset_, false);
+        checkToWireResult(expected_renderer, actual_renderer, rrset,
+                          www_name_, a_rrset_, a_rrsig_rrset_, false);
+    }
+
+    {
+        SCOPED_TRACE("without RRSIG, DNSSEC OK");
+        const TreeNodeRRset rrset(rrclass_, origin_node_, ns_rdataset_, true);
+        checkToWireResult(expected_renderer, actual_renderer, rrset,
+                          origin_name_, ns_rrset_, ConstRRsetPtr(), true);
+    }
+
+    {
+        SCOPED_TRACE("without RRSIG, DNSSEC not OK");
+        const TreeNodeRRset rrset(rrclass_, origin_node_, ns_rdataset_,
+                                  false);
+        checkToWireResult(expected_renderer, actual_renderer, rrset,
+                          origin_name_, ns_rrset_, ConstRRsetPtr(), false);
+    }
+
+    {
+        // RDATA of DNAME DR shouldn't be compressed.  Prepending "example.org"
+        // will check that.
+        SCOPED_TRACE("uncompressed RDATA");
+        const TreeNodeRRset rrset(rrclass_, origin_node_, dname_rdataset_,
+                                  false);
+        checkToWireResult(expected_renderer, actual_renderer, rrset,
+                          Name("example.org"), dname_rrset_, ConstRRsetPtr(),
+                          false);
+    }
+
+    {
+        SCOPED_TRACE("wildcard with RRSIG");
+        checkToWireResult(expected_renderer, actual_renderer,
+                          *createRRset(match_name_, rrclass_, wildcard_node_,
+                                       wildcard_rdataset_, true),
+                          origin_name_, wildmatch_rrset_,
+                          wildmatch_rrsig_rrset_, true);
+    }
+
+    {
+        SCOPED_TRACE("wildcard without RRSIG");
+        checkToWireResult(expected_renderer, actual_renderer,
+                          *createRRset(match_name_, rrclass_, wildcard_node_,
+                                       wildcard_rdataset_, false),
+                          origin_name_, wildmatch_rrset_,
+                          wildmatch_rrsig_rrset_, false);
+    }
+
+    {
+        // Very unusual case: the set only contains RRSIG (already rare)
+        // and it's requested to be dumped to wire (can only happen in
+        // ANY or type-RRSIG queries, which are rare also).  But can still
+        // happen.
+        SCOPED_TRACE("RRSIG only, DNSSEC OK");
+        const TreeNodeRRset rrset(rrclass_, www_node_, rrsig_only_rdataset_,
+                                  true);
+        checkToWireResult(expected_renderer, actual_renderer, rrset,
+                          www_name_, ConstRRsetPtr(), txt_rrsig_rrset_,true);
+    }
+
+    {
+        // Similar to the previous case, but DNSSEC records aren't requested.
+        // In practice this case wouldn't happen, but API-wise possible, so
+        // we test it explicitly.
+        SCOPED_TRACE("RRSIG only, DNSSEC not OK");
+        const TreeNodeRRset rrset(rrclass_, www_node_, rrsig_only_rdataset_,
+                                  false);
+        checkToWireResult(expected_renderer, actual_renderer, rrset,
+                          www_name_, ConstRRsetPtr(), txt_rrsig_rrset_,false);
+    }
+}
+
+TEST_F(TreeNodeRRsetTest, toWireTruncated) {
+    MessageRenderer expected_renderer, actual_renderer;
+    // dummy parameter to checkToWireResult (unused for the this test case)
+    const Name& name = Name::ROOT_NAME();
+
+    // Set the truncation limit to name len + 14 bytes of fixed data for A RR
+    // (type, class, TTL, rdlen, and 4-byte IPv4 address).  Then we can only
+    // render just one RR, without any garbage trailing data.
+    checkToWireResult(expected_renderer, actual_renderer,
+                      *createRRset(rrclass_, www_node_, a_rdataset_, true),
+                      name, a_rrset_, a_rrsig_rrset_, true,
+                      www_name_.getLength() + 14,
+                      1);   // 1 main RR, no RRSIG
+
+    // The first main RRs should fit in the renderer (the name will be
+    // fully compressed, so its size is 2 bytes), but the RRSIG doesn't.
+    checkToWireResult(expected_renderer, actual_renderer,
+                      *createRRset(rrclass_, www_node_, a_rdataset_, true),
+                      name, a_rrset_, a_rrsig_rrset_, true,
+                      www_name_.getLength() + 14 + 2 + 14,
+                      2);   // 2 main RR, no RRSIG
+
+    // This RRset has one main RR and two RRSIGs.  Rendering the second RRSIG
+    // causes truncation.
+    // First, compute the rendered length for the main RR and a single RRSIG.
+    // The length of the RRSIG should be the same if we "accidentally"
+    // rendered the RRSIG for the A RR (which only contains one RRSIG).
+    expected_renderer.clear();
+    aaaa_rrset_->toWire(expected_renderer);
+    a_rrsig_rrset_->toWire(expected_renderer);
+    const size_t limit_len = expected_renderer.getLength();
+    // Then perform the test
+    checkToWireResult(expected_renderer, actual_renderer,
+                      *createRRset(rrclass_, www_node_, aaaa_rdataset_, true),
+                      name, aaaa_rrset_, aaaa_rrsig_rrset_, true, limit_len,
+                      2);   // 1 main RR, 1 RRSIG
+
+    // RRSIG only case.  Render length limit being 1, so it won't fit,
+    // and will cause truncation.
+    checkToWireResult(expected_renderer, actual_renderer,
+                      *createRRset(rrclass_, www_node_, rrsig_only_rdataset_,
+                                   true),
+                      name, ConstRRsetPtr(), txt_rrsig_rrset_, true, 1,
+                      0);   // no RR
+}
+
+void
+checkRdataIterator(const vector<string>& expected, RdataIteratorPtr rit) {
+    for (vector<string>::const_iterator it = expected.begin();
+         it != expected.end();
+         ++it)
+    {
+        ASSERT_FALSE(rit->isLast());
+        EXPECT_EQ(*it, rit->getCurrent().toText());
+        rit->next();
+    }
+    // We should have reached the end of RDATA
+    EXPECT_TRUE(rit->isLast());
+
+    // move to the first RDATA again, and check the value.
+    rit->first();
+    if (!expected.empty()) {
+        EXPECT_EQ(expected[0], rit->getCurrent().toText());
+    } else {
+        EXPECT_TRUE(rit->isLast());
+    }
+}
+
+TEST_F(TreeNodeRRsetTest, getRdataIterator) {
+    // This RRset should have 2 A RDATAs
+    vector<string> expected;
+    expected.push_back("192.0.2.1");
+    expected.push_back("192.0.2.2");
+    checkRdataIterator(expected,
+                       TreeNodeRRset(rrclass_, www_node_, a_rdataset_, true).
+                       getRdataIterator());
+
+    // The iterator shouldn't work different with or without RRSIG
+    checkRdataIterator(expected,
+                       TreeNodeRRset(rrclass_, www_node_, a_rdataset_, false).
+                       getRdataIterator());
+
+    // This RRset should have 1 NS RDATA (containing name field)
+    expected.clear();
+    expected.push_back("ns.example.com.");
+    checkRdataIterator(expected,
+                       TreeNodeRRset(rrclass_, origin_node_, ns_rdataset_,
+                                     false).getRdataIterator());
+
+    // RRSIG only.  Iterator will be empty and shouldn't cause any disruption.
+    expected.clear();
+    checkRdataIterator(expected,
+                       TreeNodeRRset(rrclass_, www_node_, rrsig_only_rdataset_,
+                                     true).getRdataIterator());
+}
+
+void
+checkToText(const AbstractRRset& actual_rrset,
+            ConstRRsetPtr expected_rrset, ConstRRsetPtr expected_sig_rrset)
+{
+    const string actual_text = actual_rrset.toText();
+    const string expected_text =
+        (expected_rrset ? expected_rrset->toText() : "") +
+        (expected_sig_rrset ? expected_sig_rrset->toText() : "");
+    EXPECT_EQ(expected_text, actual_text);
+}
+
+TEST_F(TreeNodeRRsetTest, toText) {
+    // Constructed with RRSIG, and it should be visible.
+    checkToText(*createRRset(rrclass_, www_node_, a_rdataset_, true),
+                a_rrset_, a_rrsig_rrset_);
+    // Constructed with RRSIG, and it should be invisible.
+    checkToText(*createRRset(rrclass_, www_node_, a_rdataset_, false),
+                a_rrset_, ConstRRsetPtr());
+    // Constructed without RRSIG, and it would be visible (but of course won't)
+    checkToText(*createRRset(rrclass_, origin_node_, ns_rdataset_, true),
+                ns_rrset_, ConstRRsetPtr());
+    // Constructed without RRSIG, and it should be visible
+    checkToText(*createRRset(rrclass_, origin_node_, ns_rdataset_, false),
+                ns_rrset_, ConstRRsetPtr());
+    // Wildcard expanded name with RRSIG
+    checkToText(*createRRset(match_name_, rrclass_, wildcard_node_,
+                             wildcard_rdataset_, true),
+                wildmatch_rrset_, wildmatch_rrsig_rrset_);
+    // Wildcard expanded name without RRSIG
+    checkToText(*createRRset(match_name_, rrclass_, wildcard_node_,
+                             wildcard_rdataset_, false),
+                wildmatch_rrset_, ConstRRsetPtr());
+    // RRSIG case
+    checkToText(*createRRset(rrclass_, www_node_, rrsig_only_rdataset_,
+                             true),
+                ConstRRsetPtr(), txt_rrsig_rrset_);
+    // Similar to the previous case, but completely empty.
+    checkToText(*createRRset(rrclass_, www_node_, rrsig_only_rdataset_,
+                             false),
+                ConstRRsetPtr(), ConstRRsetPtr());
+}
+
+TEST_F(TreeNodeRRsetTest, isSameKind) {
+    const TreeNodeRRset rrset(rrclass_, www_node_, a_rdataset_, true);
+
+    // Same name (node), same type (rdataset) => same kind
+    EXPECT_TRUE(rrset.isSameKind(*createRRset(rrclass_, www_node_,
+                                              a_rdataset_, true)));
+
+    // Same name (node), different type (rdataset) => not same kind
+    EXPECT_FALSE(rrset.isSameKind(*createRRset(rrclass_, www_node_,
+                                               aaaa_rdataset_, true)));
+
+    // Different name, different type => not same kind
+    EXPECT_FALSE(rrset.isSameKind(*createRRset(rrclass_, origin_node_,
+                                               ns_rdataset_, true)));
+
+    // Different name, same type => not same kind.
+    // Note: this shouldn't happen in our in-memory data source implementation,
+    // but API doesn't prohibit it.
+    EXPECT_FALSE(rrset.isSameKind(*createRRset(rrclass_, origin_node_,
+                                               a_rdataset_, true)));
+
+    // Wildcard and expanded RRset
+    const TreeNodeRRset wildcard_rrset(rrclass_, wildcard_node_,
+                                       wildcard_rdataset_, true);
+    const TreeNodeRRset match_rrset(match_name_, rrclass_, wildcard_node_,
+                                    wildcard_rdataset_, true);
+    EXPECT_FALSE(wildcard_rrset.isSameKind(match_rrset));
+    EXPECT_FALSE(match_rrset.isSameKind(wildcard_rrset));
+
+    // Both are wildcard expanded, and have different names
+    const TreeNodeRRset match2_rrset(Name("match2.example.com"), rrclass_,
+                                     wildcard_node_, wildcard_rdataset_, true);
+    EXPECT_FALSE(match_rrset.isSameKind(match2_rrset));
+    EXPECT_FALSE(match2_rrset.isSameKind(match_rrset));
+
+    // Pathological case.  "badwild" is constructed as if expanded due to
+    // a wildcard, but has the same owner name of the wildcard itself.
+    // Technically, they should be considered of the same kind, but this
+    // implementation considers they are not.  But this case shouldn't happen
+    // as long as the RRsets are only constructed inside the in-memory
+    // zone finder implementation.
+    const TreeNodeRRset badwild_rrset(wildcard_name_, rrclass_, wildcard_node_,
+                                      wildcard_rdataset_, true);
+    EXPECT_FALSE(wildcard_rrset.isSameKind(badwild_rrset));
+    EXPECT_EQ(wildcard_rrset.toText(), badwild_rrset.toText());
+
+    // Pathological case:  Same name, same type, but different class.
+    // This case should be impossible because if the RRsets share the same
+    // tree node, they must belong to the same RR class.  This case is
+    // a caller's bug, and the isSameKind() implementation returns the
+    // "wrong" (= true) answer.
+    EXPECT_TRUE(rrset.isSameKind(*createRRset(RRClass::CH(), www_node_,
+                                              a_rdataset_, true)));
+
+    // Same kind of different RRset class
+    EXPECT_TRUE(rrset.isSameKind(*a_rrset_));
+
+    // Different kind of different RRset class
+    EXPECT_FALSE(rrset.isSameKind(*aaaa_rrset_));
+}
+
+TEST_F(TreeNodeRRsetTest, unexpectedMethods) {
+    // Note: buffer version of toWire() is checked in the toWire test.
+
+    TreeNodeRRset rrset(rrclass_, www_node_, a_rdataset_, true);
+
+    EXPECT_THROW(rrset.setTTL(RRTTL(0)), isc::Unexpected);
+    EXPECT_THROW(rrset.setName(Name("example")), isc::Unexpected);
+    EXPECT_THROW(rrset.addRdata(createRdata(RRType::A(), rrclass_, "0.0.0.0")),
+                 isc::Unexpected);
+    RdataPtr sig_rdata = createRdata(
+        RRType::RRSIG(), rrclass_,
+        "A 5 2 3600 20120814220826 20120715220826 5300 example.com. FAKE");
+    EXPECT_THROW(rrset.addRRsig(sig_rdata), isc::Unexpected);
+    EXPECT_THROW(rrset.addRRsig(*a_rrsig_rrset_), isc::Unexpected);
+    EXPECT_THROW(rrset.addRRsig(a_rrsig_rrset_), isc::Unexpected);
+    EXPECT_THROW(rrset.addRRsig(RRsetPtr()), isc::Unexpected);
+    EXPECT_THROW(rrset.removeRRsig(), isc::Unexpected);
+}
+}
diff --git a/src/lib/datasrc/tests/memory/zone_data_unittest.cc b/src/lib/datasrc/tests/memory/zone_data_unittest.cc
new file mode 100644
index 0000000..d15fe8b
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/zone_data_unittest.cc
@@ -0,0 +1,255 @@
+// 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 "memory_segment_test.h"
+
+#include <dns/rdataclass.h>
+
+#include <exceptions/exceptions.h>
+
+#include <dns/name.h>
+#include <dns/labelsequence.h>
+#include <dns/rrclass.h>
+
+#include <datasrc/memory/rdata_serialization.h>
+#include <datasrc/memory/rdataset.h>
+#include <datasrc/memory/zone_data.h>
+
+#include <testutils/dnsmessage_test.h>
+
+#include <gtest/gtest.h>
+
+#include <new>                  // for bad_alloc
+#include <string>
+
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+using namespace isc::datasrc::memory;
+using namespace isc::datasrc::memory::test;
+using namespace isc::testutils;
+
+namespace {
+
+// With this single fixture we'll test both NSEC3Data and ZoneData
+class ZoneDataTest : public ::testing::Test {
+protected:
+    ZoneDataTest() :
+        nsec3_data_(NULL), param_rdata_("1 0 12 aabbccdd"),
+        param_rdata_nosalt_("1 1 10 -"),
+        param_rdata_largesalt_("2 0 5 " + std::string(255 * 2, 'a')),
+        nsec3_rdata_("1 0 12 aabbccdd TDK23RP6 SOA"),
+        nsec3_rdata_nosalt_("1 1 10 - TDK23RP6 SOA"),
+        nsec3_rdata_largesalt_("2 0 5 " + std::string(255 * 2, 'a') +
+                               " TDK23RP6 SOA"),
+        zname_("example.com"),
+        zone_data_(ZoneData::create(mem_sgmt_, zname_)),
+        a_rrset_(textToRRset("www.example.com. 3600 IN A 192.0.2.1")),
+        aaaa_rrset_(textToRRset("www.example.com. 3600 IN AAAA 2001:db8::1")),
+        nsec3_rrset_(textToRRset("TDK23RP6.example.com. 3600 IN NSEC3 "
+                                 "1 0 12 aabbccdd TDK23RP6 SOA"))
+    {}
+    void TearDown() {
+        if (nsec3_data_ != NULL) {
+            NSEC3Data::destroy(mem_sgmt_, nsec3_data_, RRClass::IN());
+        }
+        if (zone_data_ != NULL) {
+            ZoneData::destroy(mem_sgmt_, zone_data_, RRClass::IN());
+        }
+        // detect any memory leak in the test memory segment
+        EXPECT_TRUE(mem_sgmt_.allMemoryDeallocated());
+    }
+
+    MemorySegmentTest mem_sgmt_;
+    NSEC3Data* nsec3_data_;
+    const generic::NSEC3PARAM param_rdata_, param_rdata_nosalt_,
+        param_rdata_largesalt_;
+    const generic::NSEC3 nsec3_rdata_, nsec3_rdata_nosalt_,
+        nsec3_rdata_largesalt_;
+    const Name zname_;
+    ZoneData* zone_data_;
+    const ConstRRsetPtr a_rrset_, aaaa_rrset_, nsec3_rrset_;
+    RdataEncoder encoder_;
+};
+
+// Shared by both test cases using NSEC3 and NSEC3PARAM Rdata
+template <typename RdataType>
+void
+checkNSEC3Data(MemorySegmentTest& mem_sgmt, const RdataType& expect_rdata) {
+    NSEC3Data* nsec3_data = NSEC3Data::create(mem_sgmt, expect_rdata);
+
+    // Internal tree should be created and empty.
+    EXPECT_EQ(0, nsec3_data->getNSEC3Tree().getNodeCount());
+
+    EXPECT_EQ(expect_rdata.getHashalg(), nsec3_data->hashalg);
+    EXPECT_EQ(expect_rdata.getFlags(), nsec3_data->flags);
+    EXPECT_EQ(expect_rdata.getIterations(), nsec3_data->iterations);
+    EXPECT_EQ(expect_rdata.getSalt().size(), nsec3_data->getSaltLen());
+    if (expect_rdata.getSalt().size() > 0) {
+        EXPECT_EQ(0, memcmp(&expect_rdata.getSalt()[0],
+                            nsec3_data->getSaltData(),
+                            expect_rdata.getSalt().size()));
+    }
+
+    NSEC3Data::destroy(mem_sgmt, nsec3_data, RRClass::IN());
+}
+
+void
+checkFindRdataSet(const ZoneTree& tree, const Name& name, RRType type,
+                  const RdataSet* expected_set)
+{
+    ZoneNode* node = NULL;
+    tree.find(name, &node);
+    ASSERT_NE(static_cast<ZoneNode*>(NULL), node);
+    EXPECT_EQ(expected_set, RdataSet::find(node->getData(), type));
+}
+
+TEST_F(ZoneDataTest, createNSEC3Data) {
+    // Create an NSEC3Data object from various types of RDATA (of NSEC3PARAM
+    // and of NSEC3), check if the resulting parameters match.
+    checkNSEC3Data(mem_sgmt_, param_rdata_); // one 'usual' form of params
+    checkNSEC3Data(mem_sgmt_, param_rdata_nosalt_); // empty salt
+    checkNSEC3Data(mem_sgmt_, param_rdata_largesalt_); // max-len salt
+
+    // Same concepts of the tests, using NSEC3 RDATA.
+    checkNSEC3Data(mem_sgmt_, nsec3_rdata_);
+    checkNSEC3Data(mem_sgmt_, nsec3_rdata_nosalt_);
+    checkNSEC3Data(mem_sgmt_, nsec3_rdata_largesalt_);
+}
+
+TEST_F(ZoneDataTest, addNSEC3) {
+    nsec3_data_ = NSEC3Data::create(mem_sgmt_, param_rdata_);
+
+    ZoneNode* node = NULL;
+    nsec3_data_->insertName(mem_sgmt_, nsec3_rrset_->getName(), &node);
+    ASSERT_NE(static_cast<ZoneNode*>(NULL), node);
+    EXPECT_TRUE(node->isEmpty()); // initially it should be empty
+
+    RdataSet* rdataset_nsec3 =
+        RdataSet::create(mem_sgmt_, encoder_, nsec3_rrset_, ConstRRsetPtr());
+    node->setData(rdataset_nsec3);
+
+    // Confirm we can find the added ones from the zone data.
+    checkFindRdataSet(nsec3_data_->getNSEC3Tree(), nsec3_rrset_->getName(),
+                      RRType::NSEC3(), rdataset_nsec3);
+
+    // TearDown() will confirm there's no leak on destroy
+}
+
+TEST_F(ZoneDataTest, getOriginNode) {
+    EXPECT_EQ(LabelSequence(zname_), zone_data_->getOriginNode()->getLabels());
+}
+
+TEST_F(ZoneDataTest, exceptionSafetyOnCreate) {
+    // Note: below, we use our knowledge of how memory allocation happens
+    // within the NSEC3Data, the zone data and the underlying domain tree
+    // implementation.  We'll emulate rare situations where allocate() fails
+    // with an exception, and confirm it doesn't cause any harsh disruption
+    // or leak.
+
+    // Creating internal NSEC3 tree will succeed, but allocation of NSEC3Data
+    // will fail due to bad_alloc.  It shouldn't cause memory leak
+    // (that would be caught in TearDown()).
+    mem_sgmt_.setThrowCount(2);
+    EXPECT_THROW(NSEC3Data::create(mem_sgmt_, param_rdata_), std::bad_alloc);
+
+    // allocate() will throw on the insertion of the origin node.
+    mem_sgmt_.setThrowCount(2);
+    EXPECT_THROW(ZoneData::create(mem_sgmt_, zname_), std::bad_alloc);
+
+    // allocate() will throw on creating the zone data.
+    mem_sgmt_.setThrowCount(3);
+    EXPECT_THROW(ZoneData::create(mem_sgmt_, zname_), std::bad_alloc);
+
+    // These incomplete create() attempts shouldn't cause memory leak
+    // (that would be caught in TearDown()).
+}
+
+TEST_F(ZoneDataTest, addRdataSets) {
+    // Insert a name to the zone, and add a couple the data (RdataSet) objects
+    // to the corresponding node.
+
+    ZoneNode* node = NULL;
+    zone_data_->insertName(mem_sgmt_, a_rrset_->getName(), &node);
+    ASSERT_NE(static_cast<ZoneNode*>(NULL), node);
+    EXPECT_TRUE(node->isEmpty()); // initially it should be empty
+
+    RdataSet* rdataset_a =
+        RdataSet::create(mem_sgmt_, encoder_, a_rrset_, ConstRRsetPtr());
+    node->setData(rdataset_a);
+
+    RdataSet* rdataset_aaaa =
+        RdataSet::create(mem_sgmt_, encoder_, aaaa_rrset_, ConstRRsetPtr());
+    // make a linked list and replace the list head
+    rdataset_aaaa->next = rdataset_a;
+    node->setData(rdataset_aaaa);
+
+    // Confirm we can find the added ones from the zone data.
+    checkFindRdataSet(zone_data_->getZoneTree(), a_rrset_->getName(),
+                      RRType::A(), rdataset_a);
+    checkFindRdataSet(zone_data_->getZoneTree(), a_rrset_->getName(),
+                      RRType::AAAA(), rdataset_aaaa);
+    // There's no NS (or anything other than AAAA or A) RdataSet in the list
+    checkFindRdataSet(zone_data_->getZoneTree(), a_rrset_->getName(),
+                      RRType::NS(), NULL);
+
+    // TearDown() will confirm there's no leak on destroy
+}
+
+TEST_F(ZoneDataTest, getSetNSEC3Data) {
+    // Initially there's no NSEC3 data
+    EXPECT_EQ(static_cast<NSEC3Data*>(NULL), zone_data_->getNSEC3Data());
+    // isNSEC3Signed is true iff zone data has non NULL NSEC3 data
+    EXPECT_FALSE(zone_data_->isNSEC3Signed());
+
+    // Set a new one.  The set method should return NULL.  The get method
+    // should return the new one.
+    NSEC3Data* nsec3_data = NSEC3Data::create(mem_sgmt_, param_rdata_);
+    NSEC3Data* old_nsec3_data = zone_data_->setNSEC3Data(nsec3_data);
+    EXPECT_EQ(static_cast<NSEC3Data*>(NULL), old_nsec3_data);
+    EXPECT_EQ(nsec3_data, zone_data_->getNSEC3Data());
+    EXPECT_TRUE(zone_data_->isNSEC3Signed());
+
+    // Replace an existing one with a yet another one.
+    // We're responsible for destroying the old one.
+    NSEC3Data* nsec3_data2 = NSEC3Data::create(mem_sgmt_, nsec3_rdata_);
+    old_nsec3_data = zone_data_->setNSEC3Data(nsec3_data2);
+    EXPECT_EQ(nsec3_data, old_nsec3_data);
+    EXPECT_EQ(nsec3_data2, zone_data_->getNSEC3Data());
+    EXPECT_TRUE(zone_data_->isNSEC3Signed());
+    NSEC3Data::destroy(mem_sgmt_, old_nsec3_data, RRClass::IN());
+
+    // Setting NULL clears any existing one.
+    old_nsec3_data = zone_data_->setNSEC3Data(NULL);
+    EXPECT_EQ(nsec3_data2, old_nsec3_data);
+    EXPECT_EQ(static_cast<NSEC3Data*>(NULL), zone_data_->getNSEC3Data());
+    EXPECT_FALSE(zone_data_->isNSEC3Signed());
+
+    // Then set it again.  The zone data should destroy it on its own
+    // destruction.
+    zone_data_->setNSEC3Data(old_nsec3_data);
+}
+
+TEST_F(ZoneDataTest, isSigned) {
+    // By default it's considered unsigned
+    EXPECT_FALSE(zone_data_->isSigned());
+
+    // declare it's signed, the isSigned() says so too
+    zone_data_->setSigned(true);
+    EXPECT_TRUE(zone_data_->isSigned());
+
+    // change it to unsigned again
+    zone_data_->setSigned(false);
+    EXPECT_FALSE(zone_data_->isSigned());
+}
+}
diff --git a/src/lib/datasrc/tests/memory/zone_finder_unittest.cc b/src/lib/datasrc/tests/memory/zone_finder_unittest.cc
new file mode 100644
index 0000000..494f19d
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/zone_finder_unittest.cc
@@ -0,0 +1,1604 @@
+// 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 "memory_segment_test.h"
+
+// NOTE: this faked_nsec3 inclusion (and all related code below)
+// was ported during #2109 for the convenience of implementing #2218
+// In #2218 the NSEC3 test code in this file is expected to be finalized.
+// In #2219 the original is expected to be removed, and this file should
+// probably be moved here (and any leftover code not handled in #2218 should
+// be cleaned up)
+#include "../../tests/faked_nsec3.h"
+
+#include <datasrc/memory/zone_finder.h>
+#include <datasrc/memory/rdata_serialization.h>
+#include <datasrc/data_source.h>
+#include <testutils/dnsmessage_test.h>
+
+#include <boost/foreach.hpp>
+
+#include <gtest/gtest.h>
+
+#include <string>
+
+using namespace std;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+using namespace isc::datasrc;
+using namespace isc::testutils;
+using boost::shared_ptr;
+using namespace isc::datasrc::test;
+using namespace isc::datasrc::memory::test;
+using namespace isc::datasrc::memory;
+
+namespace {
+// Commonly used result codes (Who should write the prefix all the time)
+using result::SUCCESS;
+using result::EXIST;
+
+/// \brief expensive rrset converter
+///
+/// converts any specialized rrset (which may not have implemented some
+/// methods for efficiency) into a 'full' RRsetPtr, for easy use in test
+/// checks.
+///
+/// Done very inefficiently through text representation, speed should not
+/// be a concern here.
+ConstRRsetPtr
+convertRRset(ConstRRsetPtr src) {
+    return (textToRRset(src->toText()));
+}
+
+/// \brief Test fixture for the InMemoryZoneFinder class
+class InMemoryZoneFinderTest : public ::testing::Test {
+    // A straightforward pair of textual RR(set) and a RRsetPtr variable
+    // to store the RRset.  Used to build test data below.
+    struct RRsetData {
+        const char* const text; // textual representation of an RRset
+        RRsetPtr* rrset;
+    };
+protected:
+    // The following sub tests are shared by multiple test cases, changing
+    // the zone's DNSSEC status (unsigned, NSEC-signed or NSEC3-signed).
+    // expected_flags is set to either RESULT_NSEC_SIGNED or
+    // RESULT_NSEC3_SIGNED when it's NSEC/NSEC3 signed respectively and
+    // find() is expected to set the corresponding flags.
+    // find_options should be set to FIND_DNSSEC for NSEC-signed case when
+    // NSEC is expected to be returned.
+    void findCheck(ZoneFinder::FindResultFlags expected_flags =
+                   ZoneFinder::RESULT_DEFAULT,
+                   ZoneFinder::FindOptions find_options =
+                   ZoneFinder::FIND_DEFAULT);
+    void emptyNodeCheck(ZoneFinder::FindResultFlags expected_flags =
+                        ZoneFinder::RESULT_DEFAULT);
+    void wildcardCheck(ZoneFinder::FindResultFlags expected_flags =
+                       ZoneFinder::RESULT_DEFAULT,
+                       ZoneFinder::FindOptions find_options =
+                       ZoneFinder::FIND_DEFAULT);
+    void doCancelWildcardCheck(ZoneFinder::FindResultFlags expected_flags =
+                               ZoneFinder::RESULT_DEFAULT,
+                               ZoneFinder::FindOptions find_options =
+                               ZoneFinder::FIND_DEFAULT);
+    void anyWildcardCheck(ZoneFinder::FindResultFlags expected_flags =
+                          ZoneFinder::RESULT_DEFAULT);
+    void emptyWildcardCheck(ZoneFinder::FindResultFlags expected_flags =
+                            ZoneFinder::RESULT_DEFAULT);
+    void findNSECENTCheck(const Name& ent_name,
+                          ConstRRsetPtr expected_nsec,
+                          ZoneFinder::FindResultFlags expected_flags =
+                          ZoneFinder::RESULT_DEFAULT);
+
+public:
+    InMemoryZoneFinderTest() :
+        class_(RRClass::IN()),
+        origin_("example.org"),
+        zone_data_(ZoneData::create(mem_sgmt_, origin_)),
+        zone_finder_(*zone_data_, class_)
+    {
+        // Build test RRsets.  Below, we construct an RRset for
+        // each textual RR(s) of zone_data, and assign it to the corresponding
+        // rr_xxx.
+        // Note that this contains an out-of-zone RR, and due to the
+        // validation check of masterLoad() used below, we cannot add SOA.
+        const RRsetData zone_data[] = {
+            {"example.org. 300 IN NS ns.example.org.", &rr_ns_},
+            {"example.org. 300 IN A 192.0.2.1", &rr_a_},
+            {"ns.example.org. 300 IN A 192.0.2.2", &rr_ns_a_},
+            // This one will place rr_ns_a_ at a zone cut, making it a glue:
+            {"ns.example.org. 300 IN NS 192.0.2.2", &rr_ns_ns_},
+            {"ns.example.org. 300 IN AAAA 2001:db8::2", &rr_ns_aaaa_},
+            {"cname.example.org. 300 IN CNAME canonical.example.org",
+             &rr_cname_},
+            {"cname.example.org. 300 IN A 192.0.2.3", &rr_cname_a_},
+            {"dname.example.org. 300 IN DNAME target.example.org.",
+             &rr_dname_},
+            {"dname.example.org. 300 IN A 192.0.2.39", &rr_dname_a_},
+            {"dname.example.org. 300 IN NS ns.dname.example.org.",
+             &rr_dname_ns_},
+            {"example.org. 300 IN DNAME example.com.", &rr_dname_apex_},
+            {"child.example.org. 300 IN NS ns.child.example.org.",
+             &rr_child_ns_},
+            {"child.example.org. 300 IN DS 12345 5 1 DEADBEEF",
+             &rr_child_ds_},
+            {"ns.child.example.org. 300 IN A 192.0.2.153",
+             &rr_child_glue_},
+            {"grand.child.example.org. 300 IN NS ns.grand.child.example.org.",
+             &rr_grandchild_ns_},
+            {"ns.grand.child.example.org. 300 IN AAAA 2001:db8::253",
+             &rr_grandchild_glue_},
+            {"dname.child.example.org. 300 IN DNAME example.com.",
+             &rr_child_dname_},
+            {"example.com. 300 IN A 192.0.2.10", &rr_out_},
+            {"*.wild.example.org. 300 IN A 192.0.2.1", &rr_wild_},
+            {"*.cnamewild.example.org. 300 IN CNAME canonial.example.org.",
+             &rr_cnamewild_},
+            {"foo.wild.example.org. 300 IN A 192.0.2.3", &rr_under_wild_},
+            {"wild.*.foo.example.org. 300 IN A 192.0.2.1", &rr_emptywild_},
+            {"wild.*.foo.*.bar.example.org. 300 IN A 192.0.2.1",
+             &rr_nested_emptywild_},
+            {"*.nswild.example.org. 300 IN NS nswild.example.", &rr_nswild_},
+            {"*.dnamewild.example.org. 300 IN DNAME dnamewild.example.",
+             &rr_dnamewild_},
+            {"*.child.example.org. 300 IN A 192.0.2.1", &rr_child_wild_},
+            {"bar.foo.wild.example.org. 300 IN A 192.0.2.2", &rr_not_wild_},
+            {"baz.foo.wild.example.org. 300 IN A 192.0.2.3",
+             &rr_not_wild_another_},
+            {"0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM.example.org. 300 IN "
+             "NSEC3 1 1 12 aabbccdd 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG",
+             &rr_nsec3_},
+            {"example.org. 300 IN NSEC wild.*.foo.example.org. "
+             "NS SOA RRSIG NSEC DNSKEY", &rr_nsec_},
+            // Together with the apex NSEC, these next NSECs make a complete
+            // chain in the case of the zone for the emptyNonterminal tests
+            // (We may want to clean up this generator code and/or masterLoad
+            // so that we can prepare conflicting datasets better)
+            {"wild.*.foo.example.org. 3600 IN NSEC ns.example.org. "
+             "A RRSIG NSEC", &rr_ent_nsec2_},
+            {"ns.example.org. 3600 IN NSEC foo.wild.example.org. A RRSIG NSEC",
+             &rr_ent_nsec3_},
+            {"foo.wild.example.org. 3600 IN NSEC example.org. A RRSIG NSEC",
+             &rr_ent_nsec4_},
+            // And these are NSECs used in different tests
+            {"ns.example.org. 300 IN NSEC *.nswild.example.org. A AAAA NSEC",
+             &rr_ns_nsec_},
+            {"*.wild.example.org. 300 IN NSEC foo.wild.example.org. A NSEC",
+             &rr_wild_nsec_},
+            {NULL, NULL}
+        };
+
+        for (unsigned int i = 0; zone_data[i].text != NULL; ++i) {
+            *zone_data[i].rrset = textToRRset(zone_data[i].text);
+        }
+
+    }
+
+    ~InMemoryZoneFinderTest() {
+        // Make sure we reset the hash creator to the default
+        setNSEC3HashCreator(NULL);
+        ZoneData::destroy(mem_sgmt_, zone_data_, RRClass::IN());
+    }
+
+    // NSEC3-specific call for 'loading' data
+    void addZoneDataNSEC3(const ConstRRsetPtr rrset) {
+        assert(rrset->getType() == RRType::NSEC3());
+
+        const generic::NSEC3& nsec3_rdata =
+             dynamic_cast<const generic::NSEC3&>(
+                  rrset->getRdataIterator()->getCurrent());
+
+        NSEC3Data* nsec3_data = zone_data_->getNSEC3Data();
+        if (nsec3_data == NULL) {
+             nsec3_data = NSEC3Data::create(mem_sgmt_, nsec3_rdata);
+             zone_data_->setNSEC3Data(nsec3_data);
+        } else {
+             const size_t salt_len = nsec3_data->getSaltLen();
+             const uint8_t* salt_data = nsec3_data->getSaltData();
+             const vector<uint8_t>& salt_data_2 = nsec3_rdata.getSalt();
+
+             if ((nsec3_rdata.getHashalg() != nsec3_data->hashalg) ||
+                 (nsec3_rdata.getIterations() != nsec3_data->iterations) ||
+                 (salt_data_2.size() != salt_len)) {
+                  isc_throw(isc::Unexpected,
+                            "NSEC3 with inconsistent parameters: " <<
+                            rrset->toText());
+             }
+
+             if ((salt_len > 0) &&
+                 (std::memcmp(&salt_data_2[0], salt_data, salt_len) != 0)) {
+                  isc_throw(isc::Unexpected,
+                            "NSEC3 with inconsistent parameters: " <<
+                            rrset->toText());
+             }
+        }
+
+        ZoneNode* node;
+        nsec3_data->insertName(mem_sgmt_, rrset->getName(), &node);
+
+        RdataSet* rdset = RdataSet::create(mem_sgmt_, encoder_,
+                                           rrset, ConstRRsetPtr());
+        RdataSet* old_rdset = node->setData(rdset);
+        if (old_rdset != NULL) {
+             RdataSet::destroy(mem_sgmt_, class_, old_rdset);
+        }
+        zone_data_->setSigned(true);
+    }
+
+    // simplified version of 'loading' data
+    void addZoneData(const ConstRRsetPtr rrset) {
+        ZoneNode* node = NULL;
+
+        if (rrset->getType() == RRType::NSEC3()) {
+            return (addZoneDataNSEC3(rrset));
+        } else if (rrset->getType() == RRType::NSEC()) {
+            zone_data_->setSigned(true);
+        }
+
+        zone_data_->insertName(mem_sgmt_, rrset->getName(), &node);
+
+        if (rrset->getType() == RRType::NS() &&
+            rrset->getName() != zone_data_->getOriginNode()->getName()) {
+            node->setFlag(DomainTreeNode<RdataSet>::FLAG_CALLBACK);
+        } else if (rrset->getType() == RRType::DNAME()) {
+            node->setFlag(DomainTreeNode<RdataSet>::FLAG_CALLBACK);
+        }
+
+        RdataSet* next_rds = node->getData();
+        RdataSet* rdataset =
+            RdataSet::create(mem_sgmt_, encoder_, rrset, rrset->getRRsig());
+        rdataset->next = next_rds;
+        node->setData(rdataset);
+
+        // find wildcard nodes in name (go through all of them in case there
+        // is a nonterminal one)
+        // Note that this method is pretty much equal to the 'real' loader;
+        // but less efficient
+        Name name(rrset->getName());
+        while (name.getLabelCount() > 1) {
+            if (name.isWildcard()) {
+                ZoneNode* wnode = NULL;
+                // add Wild node
+                zone_data_->insertName(mem_sgmt_, name.split(1), &wnode);
+                wnode->setFlag(ZoneData::WILDCARD_NODE);
+                // add wildcard name itself too
+                zone_data_->insertName(mem_sgmt_, name, &wnode);
+            }
+            name = name.split(1);
+        }
+
+        // If we've added NSEC3PARAM at zone origin, set up NSEC3
+        // specific data or check consistency with already set up
+        // parameters.
+        if (rrset->getType() == RRType::NSEC3PARAM() &&
+            rrset->getName() == origin_) {
+            // We know rrset has exactly one RDATA
+            const generic::NSEC3PARAM& param =
+                dynamic_cast<const generic::NSEC3PARAM&>
+                 (rrset->getRdataIterator()->getCurrent());
+
+            NSEC3Data* nsec3_data = zone_data_->getNSEC3Data();
+            if (nsec3_data == NULL) {
+                nsec3_data = NSEC3Data::create(mem_sgmt_, param);
+                zone_data_->setNSEC3Data(nsec3_data);
+                zone_data_->setSigned(true);
+            } else {
+                size_t salt_len = nsec3_data->getSaltLen();
+                const uint8_t* salt_data = nsec3_data->getSaltData();
+                const vector<uint8_t>& salt_data_2 = param.getSalt();
+
+                if ((param.getHashalg() != nsec3_data->hashalg) ||
+                    (param.getIterations() != nsec3_data->iterations) ||
+                    (salt_data_2.size() != salt_len)) {
+                     isc_throw(isc::Unexpected,
+                               "NSEC3PARAM with inconsistent parameters: "
+                               << rrset->toText());
+                }
+
+                if ((salt_len > 0) &&
+                    (std::memcmp(&salt_data_2[0],
+                                 salt_data, salt_len) != 0)) {
+                     isc_throw(isc::Unexpected,
+                               "NSEC3PARAM with inconsistent parameters: "
+                               << rrset->toText());
+                }
+            }
+        }
+    }
+
+    // Some data to test with
+    const RRClass class_;
+    const Name origin_;
+    // The zone finder to torture by tests
+    MemorySegmentTest mem_sgmt_;
+    memory::ZoneData* zone_data_;
+    memory::InMemoryZoneFinder zone_finder_;
+    isc::datasrc::memory::RdataEncoder encoder_;
+
+    // Placeholder for storing RRsets to be checked with rrsetsCheck()
+    vector<ConstRRsetPtr> actual_rrsets_;
+
+    /*
+     * Some RRsets to put inside the zone.
+     */
+    RRsetPtr
+        // Out of zone RRset
+        rr_out_,
+        // NS of example.org
+        rr_ns_,
+        // A of ns.example.org
+        rr_ns_a_,
+        // AAAA of ns.example.org
+        rr_ns_aaaa_,
+        // A of example.org
+        rr_a_;
+    RRsetPtr rr_ns_ns_;         // used to make rr_ns_a_ a glue.
+    RRsetPtr rr_cname_;         // CNAME in example.org (RDATA will be added)
+    RRsetPtr rr_cname_a_; // for mixed CNAME + A case
+    RRsetPtr rr_dname_;         // DNAME in example.org (RDATA will be added)
+    RRsetPtr rr_dname_a_; // for mixed DNAME + A case
+    RRsetPtr rr_dname_ns_; // for mixed DNAME + NS case
+    RRsetPtr rr_dname_apex_; // for mixed DNAME + NS case in the apex
+    RRsetPtr rr_child_ns_; // NS of a child domain (for delegation)
+    RRsetPtr rr_child_ds_; // DS of a child domain (for delegation, auth data)
+    RRsetPtr rr_child_glue_; // glue RR of the child domain
+    RRsetPtr rr_grandchild_ns_; // NS below a zone cut (unusual)
+    RRsetPtr rr_grandchild_glue_; // glue RR below a deeper zone cut
+    RRsetPtr rr_child_dname_; // A DNAME under NS
+    RRsetPtr rr_wild_;        // Wildcard record
+    RRsetPtr rr_cnamewild_;     // CNAME at a wildcard
+    RRsetPtr rr_emptywild_;
+    RRsetPtr rr_nested_emptywild_;
+    RRsetPtr rr_nswild_, rr_dnamewild_;
+    RRsetPtr rr_child_wild_;
+    RRsetPtr rr_under_wild_;
+    RRsetPtr rr_not_wild_;
+    RRsetPtr rr_not_wild_another_;
+    RRsetPtr rr_nsec3_;
+    RRsetPtr rr_nsec_;
+    RRsetPtr rr_ent_nsec2_;
+    RRsetPtr rr_ent_nsec3_;
+    RRsetPtr rr_ent_nsec4_;
+    RRsetPtr rr_ns_nsec_;
+    RRsetPtr rr_wild_nsec_;
+
+    /**
+     * \brief Test one find query to the zone finder.
+     *
+     * Asks a query to the zone finder and checks it does not throw and returns
+     * expected results. It returns nothing, it just signals failures
+     * to GTEST.
+     *
+     * \param name The name to ask for.
+     * \param rrtype The RRType to ask of.
+     * \param result The expected code of the result.
+     * \param check_answer Should a check against equality of the answer be
+     *     done?
+     * \param answer The expected rrset, if any should be returned.
+     * \param expected_flags The expected result flags returned via find().
+     *     These can be tested using isWildcard() etc.
+     * \param zone_finder Check different InMemoryZoneFinder object than
+     *     zone_finder_ (if NULL, uses zone_finder_)
+     * \param check_wild_answer Checks that the answer has the same RRs, type
+     *     class and TTL as the eqxpected answer and that the name corresponds
+     *     to the one searched. It is meant for checking answers for wildcard
+     *     queries.
+     */
+    void findTest(const Name& name, const RRType& rrtype,
+                  ZoneFinder::Result result,
+                  bool check_answer = true,
+                  const ConstRRsetPtr& answer = ConstRRsetPtr(),
+                  ZoneFinder::FindResultFlags expected_flags =
+                  ZoneFinder::RESULT_DEFAULT,
+                  memory::InMemoryZoneFinder* zone_finder = NULL,
+                  ZoneFinder::FindOptions options = ZoneFinder::FIND_DEFAULT,
+                  bool check_wild_answer = false)
+    {
+        SCOPED_TRACE("findTest for " + name.toText() + "/" + rrtype.toText());
+
+        if (zone_finder == NULL) {
+            zone_finder = &zone_finder_;
+        }
+        const ConstRRsetPtr answer_sig = answer ? answer->getRRsig() :
+            RRsetPtr(); // note we use the same type as of retval of getRRsig()
+        // The whole block is inside, because we need to check the result and
+        // we can't assign to FindResult
+        EXPECT_NO_THROW({
+                ZoneFinderContextPtr find_result(zone_finder->find(
+                                                     name, rrtype, options));
+                // Check it returns correct answers
+                EXPECT_EQ(result, find_result->code);
+                EXPECT_EQ((expected_flags & ZoneFinder::RESULT_WILDCARD) != 0,
+                          find_result->isWildcard());
+                EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED)
+                          != 0, find_result->isNSECSigned());
+                EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED)
+                          != 0, find_result->isNSEC3Signed());
+                if (check_answer) {
+                    if (!answer) {
+                        ASSERT_FALSE(find_result->rrset);
+                    } else {
+                        ASSERT_TRUE(find_result->rrset);
+                        ConstRRsetPtr result_rrset(
+                            convertRRset(find_result->rrset));
+                        rrsetCheck(answer, result_rrset);
+                        if (answer_sig &&
+                            (options & ZoneFinder::FIND_DNSSEC) != 0) {
+                            ASSERT_TRUE(result_rrset->getRRsig());
+                            rrsetCheck(answer_sig, result_rrset->getRRsig());
+                        } else {
+                            EXPECT_FALSE(result_rrset->getRRsig());
+                        }
+                    }
+                } else if (check_wild_answer) {
+                    ASSERT_NE(ConstRRsetPtr(), answer) <<
+                        "Wrong test, don't check for wild names if you expect "
+                        "empty answer";
+                    ASSERT_NE(ConstRRsetPtr(), find_result->rrset) <<
+                        "No answer found";
+                    // Build the expected answer using the given name and
+                    // other parameter of the base wildcard RRset.
+                    RRsetPtr wildanswer(new RRset(name, answer->getClass(),
+                                                  answer->getType(),
+                                                  answer->getTTL()));
+                    RdataIteratorPtr expectedIt(answer->getRdataIterator());
+                    for (; !expectedIt->isLast(); expectedIt->next()) {
+                        wildanswer->addRdata(expectedIt->getCurrent());
+                    }
+
+                    ConstRRsetPtr result_rrset(
+                        convertRRset(find_result->rrset));
+                    rrsetCheck(wildanswer, result_rrset);
+
+                    // Same for the RRSIG, if any.
+                    if (answer_sig) {
+                        ASSERT_TRUE(result_rrset->getRRsig());
+
+                        RRsetPtr wildsig(new RRset(name,
+                                                   answer_sig->getClass(),
+                                                   RRType::RRSIG(),
+                                                   answer_sig->getTTL()));
+                        RdataIteratorPtr expectedIt(
+                            answer_sig->getRdataIterator());
+                        for (; !expectedIt->isLast(); expectedIt->next()) {
+                            wildsig->addRdata(expectedIt->getCurrent());
+                        }
+                        rrsetCheck(wildsig, result_rrset->getRRsig());
+                    }
+                }
+            });
+    }
+    /**
+     * \brief Calls the findAll on the finder and checks the result.
+     */
+    void findAllTest(const Name& name, ZoneFinder::Result result,
+                     const vector<ConstRRsetPtr>& expected_rrsets,
+                     ZoneFinder::FindResultFlags expected_flags =
+                     ZoneFinder::RESULT_DEFAULT,
+                     memory::InMemoryZoneFinder* finder = NULL,
+                     const ConstRRsetPtr &rrset_result = ConstRRsetPtr(),
+                     ZoneFinder::FindOptions options =
+                     ZoneFinder::FIND_DEFAULT)
+    {
+        if (finder == NULL) {
+            finder = &zone_finder_;
+        }
+        std::vector<ConstRRsetPtr> target;
+        ZoneFinderContextPtr find_result(finder->findAll(name, target,
+                                                         options));
+        EXPECT_EQ(result, find_result->code);
+        if (!rrset_result) {
+            EXPECT_FALSE(find_result->rrset);
+        } else {
+            ASSERT_TRUE(find_result->rrset);
+            rrsetCheck(rrset_result, convertRRset(find_result->rrset));
+        }
+        EXPECT_EQ((expected_flags & ZoneFinder::RESULT_WILDCARD) != 0,
+                  find_result->isWildcard());
+        EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED)
+                  != 0, find_result->isNSECSigned());
+        EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED)
+                  != 0, find_result->isNSEC3Signed());
+        // Convert all rrsets to 'full' ones before checking
+        std::vector<ConstRRsetPtr> converted_rrsets;
+        BOOST_FOREACH(ConstRRsetPtr cur_rrset, target) {
+            converted_rrsets.push_back(convertRRset(cur_rrset));
+        }
+        rrsetsCheck(expected_rrsets.begin(), expected_rrsets.end(),
+                    converted_rrsets.begin(), converted_rrsets.end());
+    }
+};
+
+/**
+ * \brief Test InMemoryZoneFinder::InMemoryZoneFinder constructor.
+ *
+ * Takes the created zone finder and checks its properties they are the same
+ * as passed parameters.
+ */
+TEST_F(InMemoryZoneFinderTest, constructor) {
+    ASSERT_EQ(origin_, zone_finder_.getOrigin());
+
+    // Some unusual (abnormal case): if we add a super domain name of the
+    // zone somehow, the label of the origin node won't be absolute.
+    // getOrigin() should still be the correct one.
+    ZoneNode *node;
+    zone_data_->insertName(mem_sgmt_, Name("org"), &node);
+    ASSERT_EQ(origin_, zone_finder_.getOrigin());
+}
+
+TEST_F(InMemoryZoneFinderTest, findCNAME) {
+    // install CNAME RR
+    addZoneData(rr_cname_);
+
+    // Find A RR of the same.  Should match the CNAME
+    findTest(rr_cname_->getName(), RRType::NS(), ZoneFinder::CNAME, true,
+             rr_cname_);
+
+    // Find the CNAME itself.  Should result in normal SUCCESS
+    findTest(rr_cname_->getName(), RRType::CNAME(), ZoneFinder::SUCCESS, true,
+             rr_cname_);
+}
+
+TEST_F(InMemoryZoneFinderTest, findCNAMEUnderZoneCut) {
+    // There's nothing special when we find a CNAME under a zone cut
+    // (with FIND_GLUE_OK).  The behavior is different from BIND 9,
+    // so we test this case explicitly.
+    addZoneData(rr_child_ns_);
+    ConstRRsetPtr rr_cname_under_cut_ = textToRRset(
+        "cname.child.example.org. 300 IN CNAME target.child.example.org.");
+    addZoneData(rr_cname_under_cut_);
+    findTest(Name("cname.child.example.org"), RRType::AAAA(),
+             ZoneFinder::CNAME, true, rr_cname_under_cut_,
+             ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
+}
+
+// Search under a DNAME record. It should return the DNAME
+TEST_F(InMemoryZoneFinderTest, findBelowDNAME) {
+    EXPECT_NO_THROW(addZoneData(rr_dname_));
+    findTest(Name("below.dname.example.org"), RRType::A(), ZoneFinder::DNAME,
+             true, rr_dname_);
+}
+
+// Search at the domain with DNAME. It should act as DNAME isn't there, DNAME
+// influences only the data below (see RFC 2672, section 3)
+TEST_F(InMemoryZoneFinderTest, findAtDNAME) {
+    EXPECT_NO_THROW(addZoneData(rr_dname_));
+    EXPECT_NO_THROW(addZoneData(rr_dname_a_));
+
+    const Name dname_name(rr_dname_->getName());
+    findTest(dname_name, RRType::A(), ZoneFinder::SUCCESS, true, rr_dname_a_);
+    findTest(dname_name, RRType::DNAME(), ZoneFinder::SUCCESS, true,
+             rr_dname_);
+    findTest(dname_name, RRType::TXT(), ZoneFinder::NXRRSET, true);
+}
+
+// Try searching something that is both under NS and DNAME, without and with
+// GLUE_OK mode (it should stop at the NS and DNAME respectively).
+TEST_F(InMemoryZoneFinderTest, DNAMEUnderNS) {
+    addZoneData(rr_child_ns_);
+    addZoneData(rr_child_dname_);
+
+    Name lowName("below.dname.child.example.org.");
+
+    findTest(lowName, RRType::A(), ZoneFinder::DELEGATION, true, rr_child_ns_);
+    findTest(lowName, RRType::A(), ZoneFinder::DNAME, true, rr_child_dname_,
+             ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
+}
+
+// Test adding child zones and zone cut handling
+TEST_F(InMemoryZoneFinderTest, delegationNS) {
+    // add in-zone data
+    EXPECT_NO_THROW(addZoneData(rr_ns_));
+
+    // install a zone cut
+    EXPECT_NO_THROW(addZoneData(rr_child_ns_));
+
+    // below the zone cut
+    findTest(Name("www.child.example.org"), RRType::A(),
+             ZoneFinder::DELEGATION, true, rr_child_ns_);
+
+    // at the zone cut
+    findTest(Name("child.example.org"), RRType::A(), ZoneFinder::DELEGATION,
+             true, rr_child_ns_);
+    findTest(Name("child.example.org"), RRType::NS(), ZoneFinder::DELEGATION,
+             true, rr_child_ns_);
+
+    // finding NS for the apex (origin) node.  This must not be confused
+    // with delegation due to the existence of an NS RR.
+    findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
+
+    // unusual case of "nested delegation": the highest cut should be used.
+    EXPECT_NO_THROW(addZoneData(rr_grandchild_ns_));
+    findTest(Name("www.grand.child.example.org"), RRType::A(),
+             // note: !rr_grandchild_ns_
+             ZoneFinder::DELEGATION, true, rr_child_ns_);
+}
+
+TEST_F(InMemoryZoneFinderTest, delegationWithDS) {
+    // Similar setup to the previous one, but with DS RR at the delegation
+    // point.
+    addZoneData(rr_ns_);
+    addZoneData(rr_child_ns_);
+    addZoneData(rr_child_ds_);
+
+    // Normal types of query should result in delegation, but DS query
+    // should be considered in-zone (but only exactly at the delegation point).
+    findTest(Name("child.example.org"), RRType::A(), ZoneFinder::DELEGATION,
+             true, rr_child_ns_);
+    findTest(Name("child.example.org"), RRType::DS(), ZoneFinder::SUCCESS,
+             true, rr_child_ds_);
+    findTest(Name("grand.child.example.org"), RRType::DS(),
+             ZoneFinder::DELEGATION, true, rr_child_ns_);
+
+    // There's nothing special for DS query at the zone apex.  It would
+    // normally result in NXRRSET.
+    findTest(Name("example.org"), RRType::DS(), ZoneFinder::NXRRSET,
+             true, ConstRRsetPtr());
+}
+
+TEST_F(InMemoryZoneFinderTest, findAny) {
+    EXPECT_NO_THROW(addZoneData(rr_a_));
+    EXPECT_NO_THROW(addZoneData(rr_ns_));
+    EXPECT_NO_THROW(addZoneData(rr_child_glue_));
+
+    vector<ConstRRsetPtr> expected_sets;
+
+    // origin
+    expected_sets.push_back(rr_a_);
+    expected_sets.push_back(rr_ns_);
+    findAllTest(origin_, ZoneFinder::SUCCESS, expected_sets);
+
+    // out zone name
+    EXPECT_THROW(findAllTest(Name("example.com"), ZoneFinder::NXDOMAIN,
+                             vector<ConstRRsetPtr>()),
+                 OutOfZone);
+
+    expected_sets.clear();
+    expected_sets.push_back(rr_child_glue_);
+    findAllTest(rr_child_glue_->getName(), ZoneFinder::SUCCESS, expected_sets);
+
+    // add zone cut
+    EXPECT_NO_THROW(addZoneData(rr_child_ns_));
+
+    // zone cut
+    findAllTest(rr_child_ns_->getName(), ZoneFinder::DELEGATION,
+                vector<ConstRRsetPtr>(), ZoneFinder::RESULT_DEFAULT,
+                NULL, rr_child_ns_);
+
+    // glue for this zone cut
+    findAllTest(rr_child_glue_->getName(),ZoneFinder::DELEGATION,
+                vector<ConstRRsetPtr>(), ZoneFinder::RESULT_DEFAULT,
+                NULL, rr_child_ns_);
+}
+
+TEST_F(InMemoryZoneFinderTest, glue) {
+    // install zone data:
+    // a zone cut
+    EXPECT_NO_THROW(addZoneData(rr_child_ns_));
+    // glue for this cut
+    EXPECT_NO_THROW(addZoneData(rr_child_glue_));
+    // a nested zone cut (unusual)
+    EXPECT_NO_THROW(addZoneData(rr_grandchild_ns_));
+    // glue under the deeper zone cut
+    EXPECT_NO_THROW(addZoneData(rr_grandchild_glue_));
+    // glue 'at the' zone cut
+    EXPECT_NO_THROW(addZoneData(rr_ns_a_));
+    EXPECT_NO_THROW(addZoneData(rr_ns_ns_));
+
+    // by default glue is hidden due to the zone cut
+    findTest(rr_child_glue_->getName(), RRType::A(), ZoneFinder::DELEGATION,
+             true, rr_child_ns_);
+
+
+    // If we do it in the "glue OK" mode, we should find the exact match.
+    findTest(rr_child_glue_->getName(), RRType::A(), ZoneFinder::SUCCESS, true,
+             rr_child_glue_, ZoneFinder::RESULT_DEFAULT, NULL,
+             ZoneFinder::FIND_GLUE_OK);
+
+    // glue OK + NXRRSET case
+    findTest(rr_child_glue_->getName(), RRType::AAAA(), ZoneFinder::NXRRSET,
+             true, ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, NULL,
+             ZoneFinder::FIND_GLUE_OK);
+
+    // glue OK + NXDOMAIN case
+    findTest(Name("www.child.example.org"), RRType::A(),
+             ZoneFinder::DELEGATION, true, rr_child_ns_,
+             ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
+
+    // nested cut case.  The glue should be found.
+    findTest(rr_grandchild_glue_->getName(), RRType::AAAA(),
+             ZoneFinder::SUCCESS,
+             true, rr_grandchild_glue_, ZoneFinder::RESULT_DEFAULT, NULL,
+             ZoneFinder::FIND_GLUE_OK);
+
+    // A non-existent name in nested cut.  This should result in delegation
+    // at the highest zone cut.
+    findTest(Name("www.grand.child.example.org"), RRType::TXT(),
+             ZoneFinder::DELEGATION, true, rr_child_ns_,
+             ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
+
+    // Glue at a zone cut
+    findTest(Name("ns.example.org"), RRType::A(),
+             ZoneFinder::DELEGATION, true, rr_ns_ns_);
+    findTest(Name("ns.example.org"), RRType::A(), ZoneFinder::SUCCESS,
+             true, rr_ns_a_, ZoneFinder::RESULT_DEFAULT,
+             NULL, ZoneFinder::FIND_GLUE_OK);
+}
+
+/**
+ * \brief Test searching.
+ *
+ * Check it finds or does not find correctly and does not throw exceptions.
+ */
+void
+InMemoryZoneFinderTest::findCheck(ZoneFinder::FindResultFlags expected_flags,
+                                  ZoneFinder::FindOptions find_options)
+{
+    // Fill some data inside
+    // Now put all the data we have there. It should throw nothing
+    rr_a_->addRRsig(createRdata(RRType::RRSIG(), RRClass::IN(),
+                                "A 5 3 3600 20120814220826 20120715220826 "
+                                "1234 example.com. FAKE"));
+    EXPECT_NO_THROW(addZoneData(rr_ns_));
+    EXPECT_NO_THROW(addZoneData(rr_ns_a_));
+    EXPECT_NO_THROW(addZoneData(rr_ns_aaaa_));
+    EXPECT_NO_THROW(addZoneData(rr_a_));
+    if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
+        addZoneData(rr_nsec3_);
+        zone_data_->setSigned(true);
+    }
+    if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
+        addZoneData(rr_nsec_);
+        zone_data_->setSigned(true);
+    }
+
+    // These two should be successful
+    findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
+    findTest(rr_ns_a_->getName(), RRType::A(), ZoneFinder::SUCCESS, true,
+             rr_ns_a_);
+
+    // Similar test for a signed RRset.  We should see the RRSIG iff
+    // FIND_DNSSEC option is specified.
+    findTest(rr_a_->getName(), RRType::A(), ZoneFinder::SUCCESS, true, rr_a_);
+    findTest(rr_a_->getName(), RRType::A(), ZoneFinder::SUCCESS, true,
+             rr_a_, ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_DNSSEC);
+
+    // These domains don't exist. (and one is out of the zone).  In an
+    // NSEC-signed zone with DNSSEC records requested, it should return the
+    // covering NSEC for the query name (the actual NSEC in the test data may
+    // not really "cover" it, but for the purpose of this test it's okay).
+    ConstRRsetPtr expected_nsec; // by default it's NULL
+    if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0 &&
+        (find_options & ZoneFinder::FIND_DNSSEC) != 0) {
+        expected_nsec = rr_nsec_;
+    }
+
+    // There's no other name between this one and the origin, so when NSEC
+    // is to be returned it should be the origin NSEC.
+    findTest(Name("nothere.example.org"), RRType::A(),
+             ZoneFinder::NXDOMAIN, true, expected_nsec, expected_flags,
+             NULL, find_options);
+
+    // The previous name in the zone is "ns.example.org", but it doesn't
+    // have an NSEC.  It should be skipped and the origin NSEC will be
+    // returned as the "closest NSEC".
+    findTest(Name("nxdomain.example.org"), RRType::A(),
+             ZoneFinder::NXDOMAIN, true, expected_nsec, expected_flags,
+             NULL, find_options);
+    EXPECT_THROW(zone_finder_.find(Name("example.net"), RRType::A()),
+                 OutOfZone);
+
+    // These domain exist but don't have the provided RRType.  For the latter
+    // one we now add its NSEC (which was delayed so that it wouldn't break
+    // other cases above).
+    findTest(origin_, RRType::AAAA(), ZoneFinder::NXRRSET, true,
+             expected_nsec, expected_flags, NULL, find_options);
+
+    if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
+        addZoneData(rr_ns_nsec_);
+        zone_data_->setSigned(true);
+        if ((find_options & ZoneFinder::FIND_DNSSEC) != 0) {
+            expected_nsec = rr_ns_nsec_;
+        }
+    }
+    findTest(rr_ns_a_->getName(), RRType::NS(), ZoneFinder::NXRRSET, true,
+             expected_nsec, expected_flags, NULL, find_options);
+}
+
+TEST_F(InMemoryZoneFinderTest, find) {
+    findCheck();
+}
+
+TEST_F(InMemoryZoneFinderTest, findNSEC3Signed) {
+    findCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
+}
+
+TEST_F(InMemoryZoneFinderTest, findNSEC3SignedWithDNSSEC) {
+    // For NSEC3-signed zones, specifying the DNSSEC option shouldn't change
+    // anything (the NSEC3_SIGNED flag is always set, and no records are
+    // returned for negative cases regardless).
+    findCheck(ZoneFinder::RESULT_NSEC3_SIGNED, ZoneFinder::FIND_DNSSEC);
+}
+
+TEST_F(InMemoryZoneFinderTest, findNSECSigned) {
+    // NSEC-signed zone, without requesting DNSSEC (no NSEC should be provided)
+    findCheck(ZoneFinder::RESULT_NSEC_SIGNED);
+}
+
+// Generalized test for Empty Nonterminal (ENT) cases with NSEC
+void
+InMemoryZoneFinderTest::findNSECENTCheck(const Name& ent_name,
+    ConstRRsetPtr expected_nsec,
+    ZoneFinder::FindResultFlags expected_flags)
+{
+    addZoneData(rr_emptywild_);
+    addZoneData(rr_under_wild_);
+
+    // Sanity check: Should result in NXRRSET
+    findTest(ent_name, RRType::A(), ZoneFinder::NXRRSET, true,
+             ConstRRsetPtr(), expected_flags);
+    // Sanity check: No NSEC added yet
+    findTest(ent_name, RRType::A(), ZoneFinder::NXRRSET, true,
+             ConstRRsetPtr(), expected_flags,
+             NULL, ZoneFinder::FIND_DNSSEC);
+
+    // Now add the NSEC rrs making it a 'complete' zone (in terms of NSEC,
+    // there are no sigs)
+    addZoneData(rr_nsec_);
+    addZoneData(rr_ent_nsec2_);
+    addZoneData(rr_ent_nsec3_);
+    addZoneData(rr_ent_nsec4_);
+    zone_data_->setSigned(true);
+
+    // Should result in NXRRSET, and RESULT_NSEC_SIGNED
+    findTest(ent_name, RRType::A(), ZoneFinder::NXRRSET, true,
+             ConstRRsetPtr(),
+             expected_flags | ZoneFinder::RESULT_NSEC_SIGNED);
+
+    // And check for the NSEC if DNSSEC_OK
+    findTest(ent_name, RRType::A(), ZoneFinder::NXRRSET, true,
+             expected_nsec, expected_flags | ZoneFinder::RESULT_NSEC_SIGNED,
+             NULL, ZoneFinder::FIND_DNSSEC);
+}
+
+TEST_F(InMemoryZoneFinderTest,findNSECEmptyNonterminal) {
+    // Non-wildcard case
+    findNSECENTCheck(Name("wild.example.org"), rr_ent_nsec3_);
+}
+
+TEST_F(InMemoryZoneFinderTest, findNSECEmptyNonterminalWildcard) {
+    // Wildcard case, above actual wildcard
+    findNSECENTCheck(Name("foo.example.org"), rr_nsec_);
+}
+
+TEST_F(InMemoryZoneFinderTest, findNSECEmptyNonterminalAtWildcard) {
+    // Wildcard case, at actual wildcard
+    findNSECENTCheck(Name("bar.foo.example.org"), rr_nsec_,
+                     ZoneFinder::RESULT_WILDCARD);
+}
+
+TEST_F(InMemoryZoneFinderTest, findNSECSignedWithDNSSEC) {
+    // NSEC-signed zone, requesting DNSSEC (NSEC should be provided)
+    findCheck(ZoneFinder::RESULT_NSEC_SIGNED, ZoneFinder::FIND_DNSSEC);
+}
+
+void
+InMemoryZoneFinderTest::emptyNodeCheck(
+    ZoneFinder::FindResultFlags expected_flags)
+{
+    /*
+     * The backend RBTree for this test should look like as follows:
+     *          example.org
+     *               |
+     *              baz (empty; easy case)
+     *            /  |  \
+     *          bar  |  x.foo ('foo' part is empty; a bit trickier)
+     *              bbb
+     *             /
+     *           aaa
+     */
+
+    // Construct the test zone
+    const char* const names[] = {
+        "bar.example.org.", "x.foo.example.org.", "aaa.baz.example.org.",
+        "bbb.baz.example.org.", NULL};
+    for (int i = 0; names[i] != NULL; ++i) {
+        ConstRRsetPtr rrset = textToRRset(string(names[i]) +
+                                          " 300 IN A 192.0.2.1");
+        addZoneData(rrset);
+    }
+    if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
+        addZoneData(rr_nsec3_);
+        zone_data_->setSigned(true);
+    }
+    if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
+        addZoneData(rr_nsec_);
+        zone_data_->setSigned(true);
+    }
+
+    // empty node matching, easy case: the node for 'baz' exists with
+    // no data.
+    findTest(Name("baz.example.org"), RRType::A(), ZoneFinder::NXRRSET, true,
+             ConstRRsetPtr(), expected_flags);
+
+    // empty node matching, a trickier case: the node for 'foo' is part of
+    // "x.foo", which should be considered an empty node.
+    findTest(Name("foo.example.org"), RRType::A(), ZoneFinder::NXRRSET, true,
+             ConstRRsetPtr(), expected_flags);
+
+    // "org" is contained in "example.org", but it shouldn't be treated as
+    // NXRRSET because it's out of zone.
+    // Note: basically we don't expect such a query to be performed (the common
+    // operation is to identify the best matching zone first then perform
+    // search it), but we shouldn't be confused even in the unexpected case.
+    EXPECT_THROW(zone_finder_.find(Name("org"), RRType::A()), OutOfZone);
+}
+
+TEST_F(InMemoryZoneFinderTest, emptyNode) {
+    emptyNodeCheck();
+}
+
+TEST_F(InMemoryZoneFinderTest, emptyNodeNSEC3) {
+    emptyNodeCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
+}
+
+TEST_F(InMemoryZoneFinderTest, emptyNodeNSEC) {
+    emptyNodeCheck(ZoneFinder::RESULT_NSEC_SIGNED);
+}
+
+/*
+ * Test that puts a (simple) wildcard into the zone and checks we can
+ * correctly find the data.
+ */
+void
+InMemoryZoneFinderTest::wildcardCheck(
+    ZoneFinder::FindResultFlags expected_flags,
+    ZoneFinder::FindOptions find_options)
+{
+    /*
+     *            example.org.
+     *                 |
+     *             [cname]wild (not *.wild, should have wild mark)
+     *                 |
+     *                 *
+     */
+
+    // If the zone is "signed" (detecting it by the NSEC/NSEC3 signed flags),
+    // add RRSIGs to the records.
+    if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0 ||
+        (expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
+        // Convenience shortcut.  The RDATA is not really validatable, but
+        // it doesn't matter for our tests.
+        const char* const rrsig_common = "5 3 3600 "
+            "20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE";
+
+        find_options = find_options | ZoneFinder::FIND_DNSSEC;
+        rr_wild_->addRRsig(textToRRset("*.wild.example.org. 300 IN RRSIG A " +
+                                       string(rrsig_common)));
+        rr_cnamewild_->addRRsig(textToRRset("*.cnamewild.example.org. 300 IN "
+                                            "RRSIG CNAME " +
+                                            string(rrsig_common)));
+    }
+    addZoneData(rr_wild_);
+    addZoneData(rr_cnamewild_);
+    // If the zone is expected to be "signed" with NSEC3, add an NSEC3.
+    // (the content of the NSEC3 shouldn't matter)
+    if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
+        addZoneData(rr_nsec3_);
+    }
+    if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
+        addZoneData(rr_nsec_);
+    }
+
+    // Search at the parent. The parent will not have the A, but it will
+    // be in the wildcard (so check the wildcard isn't matched at the parent)
+    {
+        SCOPED_TRACE("Search at parent");
+        if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
+            findTest(Name("wild.example.org"), RRType::A(),
+                     ZoneFinder::NXRRSET, true, rr_nsec_, expected_flags,
+                     NULL, find_options);
+        } else {
+            findTest(Name("wild.example.org"), RRType::A(),
+                     ZoneFinder::NXRRSET, true, ConstRRsetPtr(),
+                     expected_flags, NULL, find_options);
+        }
+    }
+
+    // For the test setup of "NSEC-signed" zone, we might expect it will
+    // be returned with a negative result, either because wildcard match is
+    // disabled by the search option or because wildcard match is canceled
+    // per protocol.
+    ConstRRsetPtr expected_nsec; // by default it's NULL
+    if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0 &&
+        (find_options & ZoneFinder::FIND_DNSSEC) != 0) {
+        expected_nsec = rr_nsec_;
+    }
+    // Explicitly converting the following to const pointers; some compilers
+    // would complain about mixed use of const and non const in ?: below.
+    const ConstRRsetPtr rr_wild = rr_wild_;
+    const ConstRRsetPtr rr_cnamewild = rr_cnamewild_;
+
+    // Search the original name of wildcard
+    {
+        SCOPED_TRACE("Search directly at *");
+        findTest(Name("*.wild.example.org"), RRType::A(), ZoneFinder::SUCCESS,
+                 true, rr_wild_, ZoneFinder::RESULT_DEFAULT, NULL,
+                 find_options);
+    }
+
+    // Below some of the test cases will normally result in a wildcard match;
+    // if NO_WILDCARD is specified, it should result in NXDOMAIN instead,
+    // and, when available and requested, the covering NSEC will be returned.
+    // The following are shortcut parameters to unify these cases.
+    const bool wild_ok = ((find_options & ZoneFinder::NO_WILDCARD) == 0);
+    const ZoneFinder::FindResultFlags wild_expected_flags =
+        wild_ok ? (ZoneFinder::RESULT_WILDCARD | expected_flags) :
+        expected_flags;
+
+    // Search "created" name.
+    {
+        SCOPED_TRACE("Search at created child");
+        findTest(Name("a.wild.example.org"), RRType::A(),
+                 wild_ok ? ZoneFinder::SUCCESS : ZoneFinder::NXDOMAIN, false,
+                 wild_ok ? rr_wild : expected_nsec,
+                 wild_expected_flags, NULL, find_options, wild_ok);
+    }
+
+    // Search name that has CNAME.
+    {
+        SCOPED_TRACE("Matching CNAME");
+        findTest(Name("a.cnamewild.example.org"), RRType::A(),
+                 wild_ok ? ZoneFinder::CNAME : ZoneFinder::NXDOMAIN, false,
+                 wild_ok ? rr_cnamewild : expected_nsec,
+                 wild_expected_flags, NULL, find_options, wild_ok);
+    }
+
+    // Search another created name, this time little bit lower
+    {
+        SCOPED_TRACE("Search at created grand-child");
+        findTest(Name("a.b.wild.example.org"), RRType::A(),
+                 wild_ok ? ZoneFinder::SUCCESS : ZoneFinder::NXDOMAIN, false,
+                 wild_ok ? rr_wild : expected_nsec,
+                 wild_expected_flags, NULL, find_options, wild_ok);
+    }
+
+    addZoneData(rr_under_wild_);
+    {
+        SCOPED_TRACE("Search under non-wildcard");
+        findTest(Name("bar.foo.wild.example.org"), RRType::A(),
+                 ZoneFinder::NXDOMAIN, true, expected_nsec, expected_flags,
+                 NULL, find_options);
+    }
+
+    // Wildcard match, but no data.  We add the additional NSEC at the wildcard
+    // at this point so that it wouldn't break other tests above.  Note also
+    // that in the NO_WILDCARD case the resulting NSEC is the same.  Ideally
+    // we could use a more tricky setup so we can distinguish these cases,
+    // but for this purpose it's not bad; what we'd like to test here is that
+    // wildcard substitution doesn't happen for either case, and the
+    // NO_WILDCARD effect itself can be checked by the result code (NXDOMAIN).
+    ConstRRsetPtr expected_wild_nsec; // by default it's NULL
+    if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
+        addZoneData(rr_wild_nsec_);
+        expected_wild_nsec = rr_wild_nsec_;
+    }
+    {
+        SCOPED_TRACE("Search at wildcard, no data");
+        findTest(Name("a.wild.example.org"), RRType::AAAA(),
+                 wild_ok ? ZoneFinder::NXRRSET : ZoneFinder::NXDOMAIN, true,
+                 wild_ok ? expected_wild_nsec : expected_wild_nsec,
+                 wild_expected_flags, NULL, find_options);
+    }
+}
+
+TEST_F(InMemoryZoneFinderTest, wildcard) {
+    // Normal case
+    wildcardCheck();
+}
+
+TEST_F(InMemoryZoneFinderTest, wildcardDisabledWithNSEC) {
+    // Wildcard is disabled.  In practice, this is used as part of query
+    // processing for an NSEC-signed zone, so we test that case specifically.
+    wildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED, ZoneFinder::NO_WILDCARD);
+}
+
+TEST_F(InMemoryZoneFinderTest, wildcardDisabledWithoutNSEC) {
+    // Similar to the previous once, but check the behavior for a non signed
+    // zone just in case.
+    wildcardCheck(ZoneFinder::RESULT_DEFAULT, ZoneFinder::NO_WILDCARD);
+}
+
+/*
+ * Test that we don't match a wildcard if we get under delegation.
+ * By 4.3.3 of RFC1034:
+ * "Wildcard RRs do not apply:
+ *   - When the query is in another zone.  That is, delegation cancels
+ *     the wildcard defaults."
+ */
+TEST_F(InMemoryZoneFinderTest, delegatedWildcard) {
+    addZoneData(rr_child_wild_);
+    addZoneData(rr_child_ns_);
+
+    {
+        SCOPED_TRACE("Looking under delegation point");
+        findTest(Name("a.child.example.org"), RRType::A(),
+                 ZoneFinder::DELEGATION, true, rr_child_ns_);
+    }
+
+    {
+        SCOPED_TRACE("Looking under delegation point in GLUE_OK mode");
+        findTest(Name("a.child.example.org"), RRType::A(),
+                 ZoneFinder::DELEGATION, true, rr_child_ns_,
+                 ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
+    }
+}
+
+// Tests combination of wildcard and ANY.
+void
+InMemoryZoneFinderTest::anyWildcardCheck(
+    ZoneFinder::FindResultFlags expected_flags)
+{
+    addZoneData(rr_wild_);
+    if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
+        addZoneData(rr_nsec3_);
+    }
+    if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
+        addZoneData(rr_nsec_);
+    }
+
+    vector<ConstRRsetPtr> expected_sets;
+
+    // First try directly the name (normal match)
+    {
+        SCOPED_TRACE("Asking directly for *");
+        expected_sets.push_back(rr_wild_);
+        findAllTest(Name("*.wild.example.org"), ZoneFinder::SUCCESS,
+                    expected_sets);
+    }
+
+    // Then a wildcard match
+    {
+        SCOPED_TRACE("Asking in the wild way");
+        expected_sets.clear();
+        RRsetPtr expected(new RRset(Name("a.wild.example.org"),
+                                    rr_wild_->getClass(), rr_wild_->getType(),
+                                    rr_wild_->getTTL()));
+        expected->addRdata(rr_wild_->getRdataIterator()->getCurrent());
+        expected_sets.push_back(expected);
+        findAllTest(Name("a.wild.example.org"), ZoneFinder::SUCCESS,
+                    expected_sets,
+                    ZoneFinder::RESULT_WILDCARD | expected_flags);
+    }
+}
+
+TEST_F(InMemoryZoneFinderTest, anyWildcard) {
+    anyWildcardCheck();
+}
+
+TEST_F(InMemoryZoneFinderTest, anyWildcardNSEC3) {
+    anyWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
+}
+
+TEST_F(InMemoryZoneFinderTest, anyWildcardNSEC) {
+    anyWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED);
+}
+
+// Test there's nothing in the wildcard in the middle if we load
+// wild.*.foo.example.org.
+void
+InMemoryZoneFinderTest::emptyWildcardCheck(
+    ZoneFinder::FindResultFlags expected_flags)
+{
+    /*
+     *            example.org.
+     *                foo
+     *                 *
+     *               wild
+     */
+    addZoneData(rr_emptywild_);
+    if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
+        addZoneData(rr_nsec3_);
+    }
+    if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
+        addZoneData(rr_nsec_);
+    }
+
+    {
+        SCOPED_TRACE("Asking for the original record under wildcard");
+        findTest(Name("wild.*.foo.example.org"), RRType::A(),
+                 ZoneFinder::SUCCESS, true, rr_emptywild_);
+    }
+
+    {
+        SCOPED_TRACE("Asking for A record");
+        findTest(Name("a.foo.example.org"), RRType::A(), ZoneFinder::NXRRSET,
+                 true, ConstRRsetPtr(),
+                 ZoneFinder::RESULT_WILDCARD | expected_flags);
+        findTest(Name("*.foo.example.org"), RRType::A(), ZoneFinder::NXRRSET,
+                 true, ConstRRsetPtr(), expected_flags);
+        findTest(Name("foo.example.org"), RRType::A(), ZoneFinder::NXRRSET,
+                 true, ConstRRsetPtr(), expected_flags);
+    }
+
+    {
+        SCOPED_TRACE("Asking for ANY record");
+        findAllTest(Name("*.foo.example.org"), ZoneFinder::NXRRSET,
+                    vector<ConstRRsetPtr>(), expected_flags);
+
+        findAllTest(Name("a.foo.example.org"), ZoneFinder::NXRRSET,
+                    vector<ConstRRsetPtr>(),
+                    ZoneFinder::RESULT_WILDCARD | expected_flags);
+    }
+
+    {
+        SCOPED_TRACE("Asking on the non-terminal");
+        findTest(Name("wild.bar.foo.example.org"), RRType::A(),
+                 ZoneFinder::NXRRSET, true, ConstRRsetPtr(),
+                 ZoneFinder::RESULT_WILDCARD | expected_flags);
+    }
+}
+
+TEST_F(InMemoryZoneFinderTest, emptyWildcard) {
+    emptyWildcardCheck();
+}
+
+TEST_F(InMemoryZoneFinderTest, emptyWildcardNSEC3) {
+    emptyWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
+}
+
+TEST_F(InMemoryZoneFinderTest, emptyWildcardNSEC) {
+    emptyWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED);
+}
+
+// Same as emptyWildcard, but with multiple * in the path.
+TEST_F(InMemoryZoneFinderTest, nestedEmptyWildcard) {
+    addZoneData(rr_nested_emptywild_);
+
+    {
+        SCOPED_TRACE("Asking for the original record under wildcards");
+        findTest(Name("wild.*.foo.*.bar.example.org"), RRType::A(),
+            ZoneFinder::SUCCESS, true, rr_nested_emptywild_);
+    }
+
+    {
+        SCOPED_TRACE("Matching wildcard against empty nonterminal");
+
+        const char* names[] = {
+            "baz.foo.*.bar.example.org",
+            "baz.foo.baz.bar.example.org",
+            "*.foo.baz.bar.example.org",
+            NULL
+        };
+
+        for (const char** name = names; *name != NULL; ++ name) {
+            SCOPED_TRACE(string("Node ") + *name);
+            findTest(Name(*name), RRType::A(), ZoneFinder::NXRRSET, true,
+                     ConstRRsetPtr(), ZoneFinder::RESULT_WILDCARD);
+        }
+    }
+
+    // Domains to test
+    const char* names[] = {
+        "*.foo.*.bar.example.org",
+        "foo.*.bar.example.org",
+        "*.bar.example.org",
+        "bar.example.org",
+        NULL
+    };
+
+    {
+        SCOPED_TRACE("Asking directly for A on parent nodes");
+
+        for (const char** name = names; *name != NULL; ++ name) {
+            SCOPED_TRACE(string("Node ") + *name);
+            findTest(Name(*name), RRType::A(), ZoneFinder::NXRRSET);
+        }
+    }
+
+    {
+        SCOPED_TRACE("Asking for ANY on parent nodes");
+
+        for (const char** name = names; *name != NULL; ++ name) {
+            SCOPED_TRACE(string("Node ") + *name);
+
+            findAllTest(Name(*name), ZoneFinder::NXRRSET,
+                        vector<ConstRRsetPtr>());
+        }
+    }
+}
+
+// We run this part twice from the below test, in two slightly different
+// situations
+void
+InMemoryZoneFinderTest::doCancelWildcardCheck(
+    ZoneFinder::FindResultFlags expected_flags,
+    ZoneFinder::FindOptions find_options)
+{
+    // These should be canceled
+    {
+        SCOPED_TRACE("Canceled under foo.wild.example.org");
+
+        // For an NSEC-signed zone with DNSSEC requested, the covering NSEC
+        // should be returned.  The expected NSEC is actually just the only
+        // NSEC in the test data, but in this context it doesn't matter;
+        // it's sufficient just to check any NSEC is returned (or not).
+        ConstRRsetPtr expected_nsec; // by default it's NULL
+        if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0 &&
+            (find_options & ZoneFinder::FIND_DNSSEC)) {
+            expected_nsec = rr_nsec_;
+        }
+
+        findTest(Name("aaa.foo.wild.example.org"), RRType::A(),
+                 ZoneFinder::NXDOMAIN, true, expected_nsec, expected_flags,
+                 NULL, find_options);
+        findTest(Name("zzz.foo.wild.example.org"), RRType::A(),
+                 ZoneFinder::NXDOMAIN, true, expected_nsec, expected_flags,
+                 NULL, find_options);
+    }
+
+    // This is existing, non-wildcard domain, shouldn't wildcard at all
+    {
+        SCOPED_TRACE("Existing domain under foo.wild.example.org");
+        findTest(Name("bar.foo.wild.example.org"), RRType::A(),
+                 ZoneFinder::SUCCESS, true, rr_not_wild_);
+    }
+
+    // These should be caught by the wildcard
+    {
+        SCOPED_TRACE("Neighbor wildcards to foo.wild.example.org");
+
+        const char* names[] = {
+            "aaa.bbb.wild.example.org",
+            "aaa.zzz.wild.example.org",
+            "zzz.wild.example.org",
+            NULL
+        };
+
+        for (const char** name = names; *name != NULL; ++ name) {
+            SCOPED_TRACE(string("Node ") + *name);
+
+            findTest(Name(*name), RRType::A(), ZoneFinder::SUCCESS, false,
+                     rr_wild_,
+                     ZoneFinder::RESULT_WILDCARD | expected_flags, NULL,
+                     ZoneFinder::FIND_DEFAULT, true);
+        }
+    }
+
+    // This shouldn't be wildcarded, it's an existing domain
+    {
+        SCOPED_TRACE("The foo.wild.example.org itself");
+        findTest(Name("foo.wild.example.org"), RRType::A(),
+                 ZoneFinder::NXRRSET, true, ConstRRsetPtr(), expected_flags);
+    }
+}
+
+/*
+ * This tests that if there's a name between the wildcard domain and the
+ * searched one, it will not trigger wildcard, for example, if we have
+ * *.wild.example.org and bar.foo.wild.example.org, then we know
+ * foo.wild.example.org exists and is not wildcard. Therefore, search for
+ * aaa.foo.wild.example.org should return NXDOMAIN.
+ *
+ * Tests few cases "around" the canceled wildcard match, to see something that
+ * shouldn't be canceled isn't.
+ */
+TEST_F(InMemoryZoneFinderTest, cancelWildcard) {
+    addZoneData(rr_wild_);
+    addZoneData(rr_not_wild_);
+
+    {
+        SCOPED_TRACE("Runnig with single entry under foo.wild.example.org");
+        doCancelWildcardCheck();
+    }
+
+    // Try putting another one under foo.wild....
+    // The result should be the same but it will be done in another way in the
+    // code, because the foo.wild.example.org will exist in the tree.
+    addZoneData(rr_not_wild_another_);
+    {
+        SCOPED_TRACE("Runnig with two entries under foo.wild.example.org");
+        doCancelWildcardCheck();
+    }
+}
+
+// Same tests as cancelWildcard for NSEC3-signed zone
+TEST_F(InMemoryZoneFinderTest, cancelWildcardNSEC3) {
+    addZoneData(rr_wild_);
+    addZoneData(rr_not_wild_);
+    addZoneData(rr_nsec3_);
+
+    {
+        SCOPED_TRACE("Runnig with single entry under foo.wild.example.org");
+        doCancelWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
+    }
+    addZoneData(rr_not_wild_another_);
+    {
+        SCOPED_TRACE("Runnig with two entries under foo.wild.example.org");
+        doCancelWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
+    }
+}
+
+// Same tests as cancelWildcard for NSEC-signed zone.  Check both cases with
+// or without FIND_DNSSEC option.  NSEC should be returned only when the option
+// is given.
+TEST_F(InMemoryZoneFinderTest, cancelWildcardNSEC) {
+    addZoneData(rr_wild_);
+    addZoneData(rr_not_wild_);
+    addZoneData(rr_nsec_);
+
+    {
+        SCOPED_TRACE("Runnig with single entry under foo.wild.example.org");
+        doCancelWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED,
+                              ZoneFinder::FIND_DNSSEC);
+        doCancelWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED);
+    }
+    addZoneData(rr_not_wild_another_);
+    {
+        SCOPED_TRACE("Runnig with two entries under foo.wild.example.org");
+        doCancelWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED,
+                              ZoneFinder::FIND_DNSSEC);
+        doCancelWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED);
+    }
+}
+
+
+TEST_F(InMemoryZoneFinderTest, findNSEC3ForBadZone) {
+    // Set up the faked hash calculator.
+    const TestNSEC3HashCreator creator;
+    setNSEC3HashCreator(&creator);
+
+    // If the zone has nothing about NSEC3 (neither NSEC3 or NSEC3PARAM),
+    // findNSEC3() should be rejected.
+    EXPECT_THROW(zone_finder_.findNSEC3(Name("www.example.org"), true),
+                 DataSourceError);
+
+    // Only having NSEC3PARAM isn't enough
+    addZoneData(textToRRset("example.org. 300 IN NSEC3PARAM "
+                            "1 0 12 aabbccdd"));
+    EXPECT_THROW(zone_finder_.findNSEC3(Name("www.example.org"), true),
+                 DataSourceError);
+
+    // Unless NSEC3 for apex is added the result in the recursive mode
+    // is guaranteed.
+    const string ns1_nsec3_text = string(ns1_hash) + ".example.org." +
+        string(nsec3_common);
+    addZoneData(textToRRset(ns1_nsec3_text));
+    EXPECT_THROW(zone_finder_.findNSEC3(Name("www.example.org"), true),
+                 DataSourceError);
+}
+
+/// \brief NSEC3 specific tests fixture for the InMemoryZoneFinder class
+class InMemoryZoneFinderNSEC3Test : public InMemoryZoneFinderTest {
+public:
+    InMemoryZoneFinderNSEC3Test() {
+        // Set up the faked hash calculator.
+        setNSEC3HashCreator(&creator_);
+
+        // Add a few NSEC3 records:
+        // apex (example.org.): hash=0P..
+        // ns1.example.org:     hash=2T..
+        // w.example.org:       hash=01..
+        // zzz.example.org:     hash=R5..
+        const string apex_nsec3_text = string(apex_hash) + ".example.org." +
+            string(nsec3_common);
+        addZoneData(textToRRset(apex_nsec3_text));
+        const string ns1_nsec3_text = string(ns1_hash) + ".example.org." +
+            string(nsec3_common);
+        addZoneData(textToRRset(ns1_nsec3_text));
+        const string w_nsec3_text = string(w_hash) + ".example.org." +
+            string(nsec3_common);
+        addZoneData(textToRRset(w_nsec3_text));
+        const string zzz_nsec3_text = string(zzz_hash) + ".example.org." +
+            string(nsec3_common);
+        addZoneData(textToRRset(zzz_nsec3_text));
+    }
+
+private:
+    const TestNSEC3HashCreator creator_;
+};
+
+TEST_F(InMemoryZoneFinderNSEC3Test, findNSEC3) {
+    performNSEC3Test(zone_finder_);
+}
+
+struct TestData {
+     // String for the name passed to findNSEC3() (concatenated with
+     // "example.org.")
+     const char* const name;
+     // Should recursive findNSEC3() be performed?
+     const bool recursive;
+     // The following are members of the FindNSEC3Result returned by
+     // findNSEC3(). The proofs are given as char*, which are converted
+     // to Name objects and checked against getName() on the returned
+     // ConstRRsetPtr. If any of these is NULL, then it's expected that
+     // ConstRRsetPtr() will be returned.
+     const bool matched;
+     const uint8_t closest_labels;
+     const char* const closest_proof;
+     const char* const next_proof;
+};
+
+const TestData nsec3_data[] = {
+     // ==== These are non-recursive tests.
+     {"n0", false, false, 4, "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN", NULL},
+     {"n1", false,  true, 4, "01UDEMVP1J2F7EG6JEBPS17VP3N8I58H", NULL},
+     {"n2", false, false, 4, "01UDEMVP1J2F7EG6JEBPS17VP3N8I58H", NULL},
+     {"n3", false,  true, 4, "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM", NULL},
+     {"n4", false, false, 4, "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM", NULL},
+     {"n5", false,  true, 4, "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR", NULL},
+     {"n6", false, false, 4, "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR", NULL},
+     {"n7", false,  true, 4, "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN", NULL},
+     {"n8", false, false, 4, "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN", NULL},
+
+     // ==== These are recursive tests.
+     {"n0",  true,  true, 3, "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
+         "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN"},
+     {"n1",  true,  true, 4, "01UDEMVP1J2F7EG6JEBPS17VP3N8I58H", NULL},
+     {"n2",  true,  true, 3, "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
+         "01UDEMVP1J2F7EG6JEBPS17VP3N8I58H"},
+     {"n3",  true,  true, 4, "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM", NULL},
+     {"n4",  true,  true, 3, "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
+         "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM"},
+     {"n5",  true,  true, 4, "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR", NULL},
+     {"n6",  true,  true, 3, "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
+         "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR"},
+     {"n7",  true,  true, 4, "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN", NULL},
+     {"n8",  true,  true, 3, "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
+         "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN"}
+};
+
+const size_t data_count(sizeof(nsec3_data) / sizeof(*nsec3_data));
+
+TEST_F(InMemoryZoneFinderNSEC3Test, findNSEC3Walk) {
+    // This test basically uses nsec3_data[] declared above along with
+    // the fake hash setup to walk the NSEC3 tree. The names and fake
+    // hash calculation is specially setup so that the tree search
+    // terminates at specific locations in the tree. We findNSEC3() on
+    // each of the nsec3_data[], which is setup such that the hash
+    // results in the search terminating on either side of each node of
+    // the NSEC3 tree. This way, we check what result is returned in
+    // every search termination case in the NSEC3 tree.
+
+    const Name origin("example.org");
+    for (size_t i = 0; i < data_count; ++i) {
+        const Name name = Name(nsec3_data[i].name).concatenate(origin);
+
+        SCOPED_TRACE(name.toText() + (nsec3_data[i].recursive ?
+                                      ", recursive" :
+                                      ", non-recursive"));
+
+        const ZoneFinder::FindNSEC3Result result =
+            zone_finder_.findNSEC3(name, nsec3_data[i].recursive);
+
+        EXPECT_EQ(nsec3_data[i].matched, result.matched);
+        EXPECT_EQ(nsec3_data[i].closest_labels, result.closest_labels);
+
+        if (nsec3_data[i].closest_proof != NULL) {
+            ASSERT_TRUE(result.closest_proof);
+            EXPECT_EQ(Name(nsec3_data[i].closest_proof).concatenate(origin),
+                      result.closest_proof->getName());
+        } else {
+            EXPECT_FALSE(result.closest_proof);
+        }
+
+        if (nsec3_data[i].next_proof != NULL) {
+            ASSERT_TRUE(result.next_proof);
+            EXPECT_EQ(Name(nsec3_data[i].next_proof).concatenate(origin),
+                      result.next_proof->getName());
+        } else {
+            EXPECT_FALSE(result.next_proof);
+        }
+    }
+}
+}
diff --git a/src/lib/datasrc/tests/memory/zone_table_unittest.cc b/src/lib/datasrc/tests/memory/zone_table_unittest.cc
new file mode 100644
index 0000000..359df49
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/zone_table_unittest.cc
@@ -0,0 +1,150 @@
+// 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 <exceptions/exceptions.h>
+
+#include <util/memory_segment_local.h>
+
+#include <dns/name.h>
+#include <dns/rrclass.h>
+
+#include <datasrc/result.h>
+#include <datasrc/memory/zone_data.h>
+#include <datasrc/memory/zone_table.h>
+
+#include <gtest/gtest.h>
+
+#include <new>                  // for bad_alloc
+
+using namespace isc::dns;
+using namespace isc::datasrc;
+using namespace isc::datasrc::memory;
+
+namespace {
+// Memory segment specified for tests.  It normally behaves like a "local"
+// memory segment.  If "throw count" is set to non 0 via setThrowCount(),
+// it continues the normal behavior up to the specified number of calls to
+// allocate(), and throws an exception at the next call.
+class TestMemorySegment : public isc::util::MemorySegmentLocal {
+public:
+    TestMemorySegment() : throw_count_(0) {}
+    virtual void* allocate(size_t size) {
+        if (throw_count_ > 0) {
+            if (--throw_count_ == 0) {
+                throw std::bad_alloc();
+            }
+        }
+        return (isc::util::MemorySegmentLocal::allocate(size));
+    }
+    void setThrowCount(size_t count) { throw_count_ = count; }
+
+private:
+    size_t throw_count_;
+};
+
+class ZoneTableTest : public ::testing::Test {
+protected:
+    ZoneTableTest() : zclass_(RRClass::IN()),
+                      zname1(Name("example.com")),
+                      zname2(Name("example.net")),
+                      zname3(Name("example")),
+                      zone_table(ZoneTable::create(mem_sgmt_, zclass_))
+    {}
+    ~ZoneTableTest() {
+        if (zone_table != NULL) {
+            ZoneTable::destroy(mem_sgmt_, zone_table, zclass_);
+        }
+    }
+    void TearDown() {
+        ZoneTable::destroy(mem_sgmt_, zone_table, zclass_);
+        zone_table = NULL;
+        EXPECT_TRUE(mem_sgmt_.allMemoryDeallocated()); // catch any leak here.
+    }
+    const RRClass zclass_;
+    const Name zname1, zname2, zname3;
+    TestMemorySegment mem_sgmt_;
+    ZoneTable* zone_table;
+};
+
+TEST_F(ZoneTableTest, create) {
+    // Test about creating a zone table.  Normal case covers through other
+    // tests.  We only check exception safety by letting the test memory
+    // segment throw.
+    mem_sgmt_.setThrowCount(2);
+    EXPECT_THROW(ZoneTable::create(mem_sgmt_, zclass_), std::bad_alloc);
+    // This shouldn't cause memory leak (that would be caught in TearDown()).
+}
+
+TEST_F(ZoneTableTest, addZone) {
+    // Normal successful case.
+    const ZoneTable::AddResult result1 =
+        zone_table->addZone(mem_sgmt_, zclass_, zname1);
+    EXPECT_EQ(result::SUCCESS, result1.code);
+
+    // Duplicate add doesn't replace the existing data.
+    EXPECT_EQ(result::EXIST, zone_table->addZone(mem_sgmt_, zclass_,
+                                                 zname1).code);
+    EXPECT_EQ(result1.zone_data,
+              zone_table->addZone(mem_sgmt_, zclass_, zname1).zone_data);
+    // names are compared in a case insensitive manner.
+    EXPECT_EQ(result::EXIST, zone_table->addZone(mem_sgmt_, zclass_,
+                                                 Name("EXAMPLE.COM")).code);
+    // Add some more different ones.  Should just succeed.
+    EXPECT_EQ(result::SUCCESS,
+              zone_table->addZone(mem_sgmt_, zclass_, zname2).code);
+    EXPECT_EQ(result::SUCCESS,
+              zone_table->addZone(mem_sgmt_, zclass_, zname3).code);
+
+    // Have the memory segment throw an exception in extending the internal
+    // tree.  It still shouldn't cause memory leak (which would be detected
+    // in TearDown()).
+    mem_sgmt_.setThrowCount(2);
+    EXPECT_THROW(zone_table->addZone(mem_sgmt_, zclass_, Name("example.org")),
+                 std::bad_alloc);
+}
+
+TEST_F(ZoneTableTest, findZone) {
+    const ZoneTable::AddResult add_result1 =
+        zone_table->addZone(mem_sgmt_, zclass_, zname1);
+    EXPECT_EQ(result::SUCCESS, add_result1.code);
+    EXPECT_EQ(result::SUCCESS,
+              zone_table->addZone(mem_sgmt_, zclass_, zname2).code);
+    EXPECT_EQ(result::SUCCESS,
+              zone_table->addZone(mem_sgmt_, zclass_, zname3).code);
+
+    const ZoneTable::FindResult find_result1 =
+        zone_table->findZone(Name("example.com"));
+    EXPECT_EQ(result::SUCCESS, find_result1.code);
+    EXPECT_EQ(add_result1.zone_data, find_result1.zone_data);
+
+    EXPECT_EQ(result::NOTFOUND,
+              zone_table->findZone(Name("example.org")).code);
+    EXPECT_EQ(static_cast<ZoneData*>(NULL),
+              zone_table->findZone(Name("example.org")).zone_data);
+
+    // there's no exact match.  the result should be the longest match,
+    // and the code should be PARTIALMATCH.
+    EXPECT_EQ(result::PARTIALMATCH,
+              zone_table->findZone(Name("www.example.com")).code);
+    EXPECT_EQ(add_result1.zone_data,
+              zone_table->findZone(Name("www.example.com")).zone_data);
+
+    // make sure the partial match is indeed the longest match by adding
+    // a zone with a shorter origin and query again.
+    EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zclass_,
+                                                   Name("com")).code);
+    EXPECT_EQ(add_result1.zone_data,
+              zone_table->findZone(Name("www.example.com")).zone_data);
+}
+}
diff --git a/src/lib/datasrc/tests/memory_datasrc_unittest.cc b/src/lib/datasrc/tests/memory_datasrc_unittest.cc
index fcdca16..958c9e1 100644
--- a/src/lib/datasrc/tests/memory_datasrc_unittest.cc
+++ b/src/lib/datasrc/tests/memory_datasrc_unittest.cc
@@ -293,72 +293,6 @@ setRRset(RRsetPtr rrset, vector<RRsetPtr*>::iterator& it) {
     ++it;
 }
 
-// Some faked NSEC3 hash values commonly used in tests and the faked NSEC3Hash
-// object.
-//
-// For apex (example.org)
-const char* const apex_hash = "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
-const char* const apex_hash_lower = "0p9mhaveqvm6t7vbl5lop2u3t2rp3tom";
-// For ns1.example.org
-const char* const ns1_hash = "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR";
-// For w.example.org
-const char* const w_hash = "01UDEMVP1J2F7EG6JEBPS17VP3N8I58H";
-// For x.y.w.example.org (lower-cased)
-const char* const xyw_hash = "2vptu5timamqttgl4luu9kg21e0aor3s";
-// For zzz.example.org.
-const char* const zzz_hash = "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN";
-
-// A simple faked NSEC3 hash calculator with a dedicated creator for it.
-//
-// This is used in some NSEC3-related tests below.
-class TestNSEC3HashCreator : public NSEC3HashCreator {
-    class TestNSEC3Hash : public NSEC3Hash {
-    private:
-        typedef map<Name, string> NSEC3HashMap;
-        typedef NSEC3HashMap::value_type NSEC3HashPair;
-        NSEC3HashMap map_;
-    public:
-        TestNSEC3Hash() {
-            // Build pre-defined hash
-            map_[Name("example.org")] = apex_hash;
-            map_[Name("www.example.org")] = "2S9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
-            map_[Name("xxx.example.org")] = "Q09MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
-            map_[Name("yyy.example.org")] = "0A9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
-            map_[Name("x.y.w.example.org")] =
-                "2VPTU5TIMAMQTTGL4LUU9KG21E0AOR3S";
-            map_[Name("y.w.example.org")] = "K8UDEMVP1J2F7EG6JEBPS17VP3N8I58H";
-            map_[Name("w.example.org")] = w_hash;
-            map_[Name("zzz.example.org")] = zzz_hash;
-            map_[Name("smallest.example.org")] =
-                "00000000000000000000000000000000";
-            map_[Name("largest.example.org")] =
-                "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU";
-        }
-        virtual string calculate(const Name& name) const {
-            const NSEC3HashMap::const_iterator found = map_.find(name);
-            if (found != map_.end()) {
-                return (found->second);
-            }
-            isc_throw(isc::Unexpected, "unexpected name for NSEC3 test: "
-                      << name);
-        }
-        virtual bool match(const generic::NSEC3PARAM&) const {
-            return (true);
-        }
-        virtual bool match(const generic::NSEC3&) const {
-            return (true);
-        }
-    };
-
-public:
-    virtual NSEC3Hash* create(const generic::NSEC3PARAM&) const {
-        return (new TestNSEC3Hash);
-    }
-    virtual NSEC3Hash* create(const generic::NSEC3&) const {
-        return (new TestNSEC3Hash);
-    }
-};
-
 /// \brief Test fixture for the InMemoryZoneFinder class
 class InMemoryZoneFinderTest : public ::testing::Test {
     // A straightforward pair of textual RR(set) and a RRsetPtr variable
diff --git a/src/lib/datasrc/tests/testdata/contexttest.zone b/src/lib/datasrc/tests/testdata/contexttest.zone
index e499e0d..a39649d 100644
--- a/src/lib/datasrc/tests/testdata/contexttest.zone
+++ b/src/lib/datasrc/tests/testdata/contexttest.zone
@@ -1,7 +1,7 @@
 ;; test zone file used for ZoneFinderContext tests.
 ;; RRSIGs are (obviouslly) faked ones for testing.
 
-example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 67 3600 300 3600000 3600
+example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 71 3600 300 3600000 3600
 example.org.			      3600 IN NS	ns1.example.org.
 example.org.			      3600 IN NS	ns2.example.org.
 example.org.			      3600 IN MX	1 mx1.example.org.
@@ -71,6 +71,9 @@ a.*.emptywild.example.org.    3600 IN AAAA	2001:db8::2
 ;; expansion
 *.wildmx.example.org. 3600 IN MX 1 mx1.example.org.
 
+;; the owner name of additional for an answer RRset (MX) has DNAME
+dnamemx.example.org. 3600 IN MX 1 dname.example.org.
+
 ;; CNAME
 alias.example.org. 3600 IN CNAME cname.example.org.
 
diff --git a/src/lib/datasrc/tests/zone_finder_context_unittest.cc b/src/lib/datasrc/tests/zone_finder_context_unittest.cc
index ea02543..14429ae 100644
--- a/src/lib/datasrc/tests/zone_finder_context_unittest.cc
+++ b/src/lib/datasrc/tests/zone_finder_context_unittest.cc
@@ -14,12 +14,14 @@
 
 #include <exceptions/exceptions.h>
 
+#include <util/memory_segment_local.h>
+
 #include <dns/masterload.h>
 #include <dns/name.h>
 #include <dns/rrclass.h>
 
 #include <datasrc/zone.h>
-#include <datasrc/memory_datasrc.h>
+#include <datasrc/memory/memory_client.h>
 #include <datasrc/database.h>
 #include <datasrc/sqlite3_accessor.h>
 
@@ -39,8 +41,10 @@
 using namespace std;
 using boost::shared_ptr;
 
+using namespace isc::util;
 using namespace isc::dns;
 using namespace isc::datasrc;
+using isc::datasrc::memory::InMemoryClient;
 using namespace isc::testutils;
 
 namespace {
@@ -54,18 +58,16 @@ typedef shared_ptr<DataSourceClient> DataSourceClientPtr;
 // This is the type used as the test parameter.  Note that this is
 // intentionally a plain old type (i.e. a function pointer), not a class;
 // otherwise it could cause initialization fiasco at the instantiation time.
-typedef DataSourceClientPtr (*ClientCreator)(RRClass, const Name&);
+typedef DataSourceClientPtr (*ClientCreator)(MemorySegment&, RRClass,
+                                             const Name&);
 
 // Creator for the in-memory client to be tested
 DataSourceClientPtr
-createInMemoryClient(RRClass zclass, const Name& zname) {
-    shared_ptr<InMemoryClient> client(new InMemoryClient);
-
-    shared_ptr<InMemoryZoneFinder> finder(
-        new InMemoryZoneFinder(zclass, zname));
-    finder->load(TEST_ZONE_FILE);
-
-    client->addZone(finder);
+createInMemoryClient(MemorySegment& mem_sgmt, RRClass zclass,
+                     const Name& zname)
+{
+    shared_ptr<InMemoryClient> client(new InMemoryClient(mem_sgmt, zclass));
+    client->load(zname, TEST_ZONE_FILE);
 
     return (client);
 }
@@ -76,7 +78,7 @@ addRRset(ZoneUpdaterPtr updater, ConstRRsetPtr rrset) {
 }
 
 DataSourceClientPtr
-createSQLite3Client(RRClass zclass, const Name& zname) {
+createSQLite3Client(MemorySegment&, RRClass zclass, const Name& zname) {
     // We always begin with an empty template SQLite3 DB file and install
     // the zone data from the zone file to ensure both cases have the
     // same test data.
@@ -103,7 +105,7 @@ class ZoneFinderContextTest :
 {
 protected:
     ZoneFinderContextTest() : qclass_(RRClass::IN()), qzone_("example.org") {
-        client_ = (*GetParam())(qclass_, qzone_);
+        client_ = (*GetParam())(mem_sgmt_, qclass_, qzone_);
         REQUESTED_A.push_back(RRType::A());
         REQUESTED_AAAA.push_back(RRType::AAAA());
         REQUESTED_BOTH.push_back(RRType::A());
@@ -114,6 +116,7 @@ protected:
         ASSERT_TRUE(finder_);
     }
 
+    MemorySegmentLocal mem_sgmt_;
     const RRClass qclass_;
     const Name qzone_;
     DataSourceClientPtr client_;
@@ -232,6 +235,18 @@ TEST_P(ZoneFinderContextTest, getAdditionalDelegationWithDname) {
                 result_sets_.begin(), result_sets_.end());
 }
 
+TEST_P(ZoneFinderContextTest, getAdditionalOnDname) {
+    // The additional name has a DNAME as well as the additional record.
+    // The existence of DNAME shouldn't hide the additional record.
+    ZoneFinderContextPtr ctx = finder_->find(Name("dnamemx.example.org"),
+                                             RRType::MX());
+    EXPECT_EQ(ZoneFinder::SUCCESS, ctx->code);
+
+    ctx->getAdditional(REQUESTED_BOTH, result_sets_);
+    rrsetsCheck("dname.example.org. 3600 IN A 192.0.2.12\n",
+                result_sets_.begin(), result_sets_.end());
+}
+
 TEST_P(ZoneFinderContextTest, getAdditionalDelegationWithEmptyName) {
     // One of NS names is at an empty non terminal node.  It shouldn't cause
     // any disruption.
diff --git a/src/lib/dns/labelsequence.cc b/src/lib/dns/labelsequence.cc
index ed23f26..f5f6a95 100644
--- a/src/lib/dns/labelsequence.cc
+++ b/src/lib/dns/labelsequence.cc
@@ -45,8 +45,7 @@ LabelSequence::LabelSequence(const void* buf) {
     // Check the integrity on the offsets and the name data
     const uint8_t* dp = data_;
     for (size_t cur_offset = 0; cur_offset < offsets_len; ++cur_offset) {
-        if (offsets_[cur_offset] > Name::MAX_LABELLEN ||
-            dp - data_ != offsets_[cur_offset]) {
+        if (dp - data_ != offsets_[cur_offset] || *dp > Name::MAX_LABELLEN) {
             isc_throw(BadValue,
                       "Broken offset or name data in serialized "
                       "LabelSequence data");
diff --git a/src/lib/dns/nsec3hash.cc b/src/lib/dns/nsec3hash.cc
index 159dff3..8fe3cf1 100644
--- a/src/lib/dns/nsec3hash.cc
+++ b/src/lib/dns/nsec3hash.cc
@@ -16,6 +16,7 @@
 
 #include <cassert>
 #include <cstring>
+#include <cstdlib>
 #include <string>
 #include <vector>
 
@@ -57,17 +58,31 @@ private:
 
 public:
     NSEC3HashRFC5155(uint8_t algorithm, uint16_t iterations,
-                     const vector<uint8_t>& salt) :
+                     const uint8_t* salt_data, size_t salt_length) :
         algorithm_(algorithm), iterations_(iterations),
-        salt_(salt), digest_(SHA1_HASHSIZE), obuf_(Name::MAX_WIRE)
+        salt_data_(NULL), salt_length_(salt_length),
+        digest_(SHA1_HASHSIZE), obuf_(Name::MAX_WIRE)
     {
         if (algorithm_ != NSEC3_HASH_SHA1) {
             isc_throw(UnknownNSEC3HashAlgorithm, "Unknown NSEC3 algorithm: " <<
                       static_cast<unsigned int>(algorithm_));
         }
+
+        if (salt_length > 0) {
+            salt_data_ = static_cast<uint8_t*>(std::malloc(salt_length));
+            if (salt_data_ == NULL) {
+                throw std::bad_alloc();
+            }
+            std::memcpy(salt_data_, salt_data, salt_length);
+        }
+
         SHA1Reset(&sha1_ctx_);
     }
 
+    virtual ~NSEC3HashRFC5155() {
+        std::free(salt_data_);
+    }
+
     virtual std::string calculate(const Name& name) const;
 
     virtual bool match(const generic::NSEC3& nsec3) const;
@@ -78,7 +93,8 @@ public:
 private:
     const uint8_t algorithm_;
     const uint16_t iterations_;
-    const vector<uint8_t> salt_;
+    uint8_t* salt_data_;
+    const size_t salt_length_;
 
     // The following members are placeholder of work place and don't hold
     // any state over multiple calls so can be mutable without breaking
@@ -108,15 +124,14 @@ NSEC3HashRFC5155::calculate(const Name& name) const {
     name_copy.downcase();
     name_copy.toWire(obuf_);
 
-    const uint8_t saltlen = salt_.size();
-    const uint8_t* const salt = (saltlen > 0) ? &salt_[0] : NULL;
     uint8_t* const digest = &digest_[0];
     assert(digest_.size() == SHA1_HASHSIZE);
 
     iterateSHA1(&sha1_ctx_, static_cast<const uint8_t*>(obuf_.getData()),
-                obuf_.getLength(), salt, saltlen, digest);
+                obuf_.getLength(), salt_data_, salt_length_, digest);
     for (unsigned int n = 0; n < iterations_; ++n) {
-        iterateSHA1(&sha1_ctx_, digest, SHA1_HASHSIZE, salt, saltlen, digest);
+        iterateSHA1(&sha1_ctx_, digest, SHA1_HASHSIZE,
+                    salt_data_, salt_length_, digest);
     }
 
     return (encodeBase32Hex(digest_));
@@ -127,8 +142,9 @@ NSEC3HashRFC5155::match(uint8_t algorithm, uint16_t iterations,
                         const vector<uint8_t>& salt) const
 {
     return (algorithm_ == algorithm && iterations_ == iterations &&
-            salt_.size() == salt.size() &&
-            (salt_.empty() || memcmp(&salt_[0], &salt[0], salt_.size()) == 0));
+            salt_length_ == salt.size() &&
+            ((salt_length_ == 0) ||
+             memcmp(salt_data_, &salt[0], salt_length_) == 0));
 }
 
 bool
@@ -175,15 +191,35 @@ NSEC3Hash::create(const generic::NSEC3& nsec3) {
 }
 
 NSEC3Hash*
+NSEC3Hash::create(uint8_t algorithm, uint16_t iterations,
+                  const uint8_t* salt_data, size_t salt_length) {
+    return (getNSEC3HashCreator()->create(algorithm, iterations,
+                                          salt_data, salt_length));
+}
+
+NSEC3Hash*
 DefaultNSEC3HashCreator::create(const generic::NSEC3PARAM& param) const {
+    const vector<uint8_t>& salt = param.getSalt();
     return (new NSEC3HashRFC5155(param.getHashalg(), param.getIterations(),
-                                 param.getSalt()));
+                                 salt.empty() ? NULL : &salt[0],
+                                 salt.size()));
 }
 
 NSEC3Hash*
 DefaultNSEC3HashCreator::create(const generic::NSEC3& nsec3) const {
+    const vector<uint8_t>& salt = nsec3.getSalt();
     return (new NSEC3HashRFC5155(nsec3.getHashalg(), nsec3.getIterations(),
-                                 nsec3.getSalt()));
+                                 salt.empty() ? NULL : &salt[0],
+                                 salt.size()));
+}
+
+NSEC3Hash*
+DefaultNSEC3HashCreator::create(uint8_t algorithm, uint16_t iterations,
+                                const uint8_t* salt_data,
+                                size_t salt_length) const
+{
+    return (new NSEC3HashRFC5155(algorithm, iterations,
+                                 salt_data, salt_length));
 }
 
 void
diff --git a/src/lib/dns/nsec3hash.h b/src/lib/dns/nsec3hash.h
index 2056708..e082ee8 100644
--- a/src/lib/dns/nsec3hash.h
+++ b/src/lib/dns/nsec3hash.h
@@ -16,7 +16,8 @@
 #define __NSEC3HASH_H 1
 
 #include <string>
-
+#include <vector>
+#include <stdint.h>
 #include <exceptions/exceptions.h>
 
 namespace isc {
@@ -115,6 +116,16 @@ public:
     /// for hash calculation from an NSEC3 RDATA object.
     static NSEC3Hash* create(const rdata::generic::NSEC3& nsec3);
 
+    /// \brief Factory method of NSECHash from args.
+    ///
+    /// \param algorithm the NSEC3 algorithm to use; currently only 1
+    ///                  (SHA-1) is supported
+    /// \param iterations the number of iterations
+    /// \param salt_data the salt data as a byte array
+    /// \param salt_data_length the length of the salt data
+    static NSEC3Hash* create(uint8_t algorithm, uint16_t iterations,
+                             const uint8_t* salt_data, size_t salt_length);
+
     /// \brief The destructor.
     virtual ~NSEC3Hash() {}
 
@@ -167,7 +178,7 @@ public:
 /// would be an experimental extension for a newer hash algorithm or
 /// implementation.
 ///
-/// The two main methods named \c create() correspond to the static factory
+/// The three main methods named \c create() correspond to the static factory
 /// methods of \c NSEC3Hash of the same name.
 ///
 /// By default, the library uses the \c DefaultNSEC3HashCreator creator.
@@ -210,6 +221,22 @@ public:
     /// <code>NSEC3Hash::create(const rdata::generic::NSEC3& param)</code>
     virtual NSEC3Hash* create(const rdata::generic::NSEC3& nsec3)
         const = 0;
+
+    /// \brief Factory method of NSECHash from args.
+    ///
+    /// See
+    /// <code>NSEC3Hash::create(uint8_t algorithm, uint16_t iterations,
+    ///                         const uint8_t* salt_data,
+    ///                         size_t salt_length)</code>
+    ///
+    /// \param algorithm the NSEC3 algorithm to use; currently only 1
+    ///                  (SHA-1) is supported
+    /// \param iterations the number of iterations
+    /// \param salt_data the salt data as a byte array
+    /// \param salt_data_length the length of the salt data
+    virtual NSEC3Hash* create(uint8_t algorithm, uint16_t iterations,
+                              const uint8_t* salt_data, size_t salt_length)
+        const = 0;
 };
 
 /// \brief The default NSEC3Hash creator.
@@ -225,6 +252,9 @@ class DefaultNSEC3HashCreator : public NSEC3HashCreator {
 public:
     virtual NSEC3Hash* create(const rdata::generic::NSEC3PARAM& param) const;
     virtual NSEC3Hash* create(const rdata::generic::NSEC3& nsec3) const;
+    virtual NSEC3Hash* create(uint8_t algorithm, uint16_t iterations,
+                              const uint8_t* salt_data,
+                              size_t salt_length) const;
 };
 
 /// \brief The registrar of \c NSEC3HashCreator.
diff --git a/src/lib/dns/tests/labelsequence_unittest.cc b/src/lib/dns/tests/labelsequence_unittest.cc
index b7463b2..90d470d 100644
--- a/src/lib/dns/tests/labelsequence_unittest.cc
+++ b/src/lib/dns/tests/labelsequence_unittest.cc
@@ -12,6 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <util/buffer.h>
+
 #include <dns/labelsequence.h>
 #include <dns/name.h>
 #include <exceptions/exceptions.h>
@@ -772,6 +774,37 @@ TEST_F(LabelSequenceTest, serialize) {
         1, 0, 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e' };
     expected.push_back(DataPair(sizeof(expected_data5), expected_data5));
 
+    // Labels containing a longest possible label
+    const Name name_longlabel(std::string(63, 'x')); // 63 'x's
+    LabelSequence ls_longlabel(name_longlabel);
+    actual_labelseqs.push_back(ls_longlabel);
+    vector<uint8_t> expected_data6;
+    expected_data6.push_back(2); // 2 labels
+    expected_data6.push_back(0); // 1st offset
+    expected_data6.push_back(64); // 2nd offset
+    expected_data6.push_back(63); // 1st label length
+    expected_data6.insert(expected_data6.end(), 63, 'x'); // 1st label: 63 'x's
+    expected_data6.push_back(0); // 2nd label: trailing 0
+    expected.push_back(DataPair(expected_data6.size(), &expected_data6[0]));
+
+    // Max number of labels and longest possible name
+    EXPECT_EQ(Name::MAX_WIRE, n_maxlabel.getLength());
+    LabelSequence ls_maxlabel(n_maxlabel);
+    actual_labelseqs.push_back(ls_maxlabel);
+    vector<uint8_t> expected_data7;
+    expected_data7.push_back(Name::MAX_LABELS); // number of labels
+    for (size_t i = 0; i < Name::MAX_LABELS; ++i) {
+        expected_data7.push_back(i * 2); // each label has length and 1 byte
+    }
+    // Copy wire data of the name
+    isc::util::OutputBuffer ob(0);
+    n_maxlabel.toWire(ob);
+    expected_data7.insert(expected_data7.end(),
+                          static_cast<const uint8_t*>(ob.getData()),
+                          static_cast<const uint8_t*>(ob.getData()) +
+                          ob.getLength());
+    expected.push_back(DataPair(expected_data7.size(), &expected_data7[0]));
+
     // For each data set, serialize the labels and compare the data to the
     // expected one.
     vector<DataPair>::const_iterator it = expected.begin();
diff --git a/src/lib/dns/tests/nsec3hash_unittest.cc b/src/lib/dns/tests/nsec3hash_unittest.cc
index e607c74..4ef0c7b 100644
--- a/src/lib/dns/tests/nsec3hash_unittest.cc
+++ b/src/lib/dns/tests/nsec3hash_unittest.cc
@@ -20,11 +20,14 @@
 
 #include <dns/nsec3hash.h>
 #include <dns/rdataclass.h>
+#include <util/encode/hex.h>
 
 using boost::scoped_ptr;
 using namespace std;
 using namespace isc::dns;
 using namespace isc::dns::rdata;
+using namespace isc::util;
+using namespace isc::util::encode;
 
 namespace {
 typedef scoped_ptr<NSEC3Hash> NSEC3HashPtr;
@@ -39,7 +42,10 @@ protected:
         test_hash_nsec3(NSEC3Hash::create(generic::NSEC3
                                           ("1 0 12 aabbccdd " +
                                            string(nsec3_common))))
-    {}
+    {
+        const uint8_t salt[] = {0xaa, 0xbb, 0xcc, 0xdd};
+        test_hash_args.reset(NSEC3Hash::create(1, 12, salt, sizeof(salt)));
+    }
 
     ~NSEC3HashTest() {
         // Make sure we reset the hash creator to the default
@@ -53,6 +59,9 @@ protected:
 
     // Similar to test_hash, but created from NSEC3 RR.
     NSEC3HashPtr test_hash_nsec3;
+
+    // Similar to test_hash, but created from passed args.
+    NSEC3HashPtr test_hash_args;
 };
 
 TEST_F(NSEC3HashTest, unknownAlgorithm) {
@@ -65,6 +74,10 @@ TEST_F(NSEC3HashTest, unknownAlgorithm) {
                          generic::NSEC3("2 0 12 aabbccdd " +
                                         string(nsec3_common)))),
                      UnknownNSEC3HashAlgorithm);
+
+    const uint8_t salt[] = {0xaa, 0xbb, 0xcc, 0xdd};
+    EXPECT_THROW(NSEC3HashPtr(NSEC3Hash::create(2, 12, salt, sizeof(salt))),
+                 UnknownNSEC3HashAlgorithm);
 }
 
 // Common checks for NSEC3 hash calculation
@@ -90,6 +103,10 @@ TEST_F(NSEC3HashTest, calculate) {
         SCOPED_TRACE("calculate check with NSEC3 based hash");
         calculateCheck(*test_hash_nsec3);
     }
+    {
+        SCOPED_TRACE("calculate check with args based hash");
+        calculateCheck(*test_hash_args);
+    }
 
     // Some boundary cases: 0-iteration and empty salt.  Borrowed from the
     // .com zone data.
@@ -177,6 +194,11 @@ public:
         }
         return (new TestNSEC3Hash);
     }
+    virtual NSEC3Hash* create(uint8_t, uint16_t,
+                              const uint8_t*, size_t) const {
+        isc_throw(isc::Unexpected,
+                  "This method is not implemented here.");
+    }
 private:
     DefaultNSEC3HashCreator default_creator_;
 };
diff --git a/src/lib/python/isc/datasrc/tests/clientlist_test.py b/src/lib/python/isc/datasrc/tests/clientlist_test.py
index 54b20e1..ea39d4e 100644
--- a/src/lib/python/isc/datasrc/tests/clientlist_test.py
+++ b/src/lib/python/isc/datasrc/tests/clientlist_test.py
@@ -28,6 +28,16 @@ class ClientListTest(unittest.TestCase):
     contain the ConfigurableClientList only.
     """
 
+    def tearDown(self):
+        # The unit test module could keep internal objects alive longer than
+        # we expect.  But cached zone finder and cache client cannot stay
+        # longer than the originating client list.  So we explicitly clean
+        # them up here.  The ordering is important: clist must be destroyed
+        # last.
+        self.dsrc = None
+        self.finder = None
+        self.clist = None
+
     def test_constructors(self):
         """
         Test the constructor. It should accept an RRClass. Check it
@@ -50,16 +60,16 @@ class ClientListTest(unittest.TestCase):
         ones are acceptend and invalid rejected. We check the changes
         have effect.
         """
-        clist = isc.datasrc.ConfigurableClientList(isc.dns.RRClass.IN())
+        self.clist = isc.datasrc.ConfigurableClientList(isc.dns.RRClass.IN())
         # This should be NOP now
-        clist.configure("[]", True)
+        self.clist.configure("[]", True)
         # Check the zone is not there yet
-        dsrc, finder, exact = clist.find(isc.dns.Name("example.org"))
+        dsrc, finder, exact = self.clist.find(isc.dns.Name("example.org"))
         self.assertIsNone(dsrc)
         self.assertIsNone(finder)
         self.assertFalse(exact)
         # We can use this type, as it is not loaded dynamically.
-        clist.configure('''[{
+        self.clist.configure('''[{
             "type": "MasterFiles",
             "params": {
                 "example.org": "''' + TESTDATA_PATH + '''example.org.zone"
@@ -68,38 +78,39 @@ class ClientListTest(unittest.TestCase):
         }]''', True)
         # Check the zone is there now. Proper tests of find are in other
         # test methods.
-        dsrc, finder, exact = clist.find(isc.dns.Name("example.org"))
-        self.assertIsNotNone(dsrc)
-        self.assertTrue(isinstance(dsrc, isc.datasrc.DataSourceClient))
-        self.assertIsNotNone(finder)
-        self.assertTrue(isinstance(finder, isc.datasrc.ZoneFinder))
+        self.dsrc, self.finder, exact = \
+            self.clist.find(isc.dns.Name("example.org"))
+        self.assertIsNotNone(self.dsrc)
+        self.assertTrue(isinstance(self.dsrc, isc.datasrc.DataSourceClient))
+        self.assertIsNotNone(self.finder)
+        self.assertTrue(isinstance(self.finder, isc.datasrc.ZoneFinder))
         self.assertTrue(exact)
-        self.assertRaises(isc.datasrc.Error, clist.configure, '"bad type"',
-                          True)
-        self.assertRaises(isc.datasrc.Error, clist.configure, '''[{
+        self.assertRaises(isc.datasrc.Error, self.clist.configure,
+                          '"bad type"', True)
+        self.assertRaises(isc.datasrc.Error, self.clist.configure, '''[{
             "type": "bad type"
         }]''', True)
-        self.assertRaises(isc.datasrc.Error, clist.configure, '''[{
+        self.assertRaises(isc.datasrc.Error, self.clist.configure, '''[{
             bad JSON,
         }]''', True)
-        self.assertRaises(TypeError, clist.configure, [], True)
-        self.assertRaises(TypeError, clist.configure, "[]")
-        self.assertRaises(TypeError, clist.configure, "[]", "true")
+        self.assertRaises(TypeError, self.clist.configure, [], True)
+        self.assertRaises(TypeError, self.clist.configure, "[]")
+        self.assertRaises(TypeError, self.clist.configure, "[]", "true")
 
     def test_find(self):
         """
         Test the find accepts the right arguments, some of them can be omitted,
         etc.
         """
-        clist = isc.datasrc.ConfigurableClientList(isc.dns.RRClass.IN())
-        clist.configure('''[{
+        self.clist = isc.datasrc.ConfigurableClientList(isc.dns.RRClass.IN())
+        self.clist.configure('''[{
             "type": "MasterFiles",
             "params": {
                 "example.org": "''' + TESTDATA_PATH + '''example.org.zone"
             },
             "cache-enable": true
         }]''', True)
-        dsrc, finder, exact = clist.find(isc.dns.Name("sub.example.org"))
+        dsrc, finder, exact = self.clist.find(isc.dns.Name("sub.example.org"))
         self.assertIsNotNone(dsrc)
         self.assertTrue(isinstance(dsrc, isc.datasrc.DataSourceClient))
         self.assertIsNotNone(finder)
@@ -112,33 +123,33 @@ class ClientListTest(unittest.TestCase):
         self.assertEqual(2, sys.getrefcount(dsrc))
         # We check an exact match in test_configure already
         self.assertFalse(exact)
-        dsrc, finder, exact = clist.find(isc.dns.Name("sub.example.org"),
-                                         False)
-        self.assertIsNotNone(dsrc)
-        self.assertTrue(isinstance(dsrc, isc.datasrc.DataSourceClient))
-        self.assertIsNotNone(finder)
-        self.assertTrue(isinstance(finder, isc.datasrc.ZoneFinder))
+        self.dsrc, self.finder, exact = \
+            self.clist.find(isc.dns.Name("sub.example.org"), False)
+        self.assertIsNotNone(self.dsrc)
+        self.assertTrue(isinstance(self.dsrc, isc.datasrc.DataSourceClient))
+        self.assertIsNotNone(self.finder)
+        self.assertTrue(isinstance(self.finder, isc.datasrc.ZoneFinder))
         self.assertFalse(exact)
-        dsrc, finder, exact = clist.find(isc.dns.Name("sub.example.org"),
-                                         True)
-        self.assertIsNone(dsrc)
-        self.assertIsNone(finder)
+        self.dsrc, self.finder, exact = \
+            self.clist.find(isc.dns.Name("sub.example.org"), True)
+        self.assertIsNone(self.dsrc)
+        self.assertIsNone(self.finder)
         self.assertFalse(exact)
-        dsrc, finder, exact = clist.find(isc.dns.Name("sub.example.org"),
-                                         False, False)
-        self.assertIsNotNone(dsrc)
-        self.assertTrue(isinstance(dsrc, isc.datasrc.DataSourceClient))
-        self.assertIsNotNone(finder)
-        self.assertTrue(isinstance(finder, isc.datasrc.ZoneFinder))
+        self.dsrc, self.finder, exact = \
+            self.clist.find(isc.dns.Name("sub.example.org"), False, False)
+        self.assertIsNotNone(self.dsrc)
+        self.assertTrue(isinstance(self.dsrc, isc.datasrc.DataSourceClient))
+        self.assertIsNotNone(self.finder)
+        self.assertTrue(isinstance(self.finder, isc.datasrc.ZoneFinder))
         self.assertFalse(exact)
-        dsrc, finder, exact = clist.find(isc.dns.Name("sub.example.org"),
-                                         True, False)
-        self.assertIsNone(dsrc)
-        self.assertIsNone(finder)
+        self.dsrc, self.finder, exact = \
+            self.clist.find(isc.dns.Name("sub.example.org"), True, False)
+        self.assertIsNone(self.dsrc)
+        self.assertIsNone(self.finder)
         self.assertFalse(exact)
         # Some invalid inputs
-        self.assertRaises(TypeError, clist.find, "example.org")
-        self.assertRaises(TypeError, clist.find)
+        self.assertRaises(TypeError, self.clist.find, "example.org")
+        self.assertRaises(TypeError, self.clist.find)
 
 if __name__ == "__main__":
     isc.log.init("bind10")



More information about the bind10-changes mailing list