"Fossies" - the Fresh Open Source Software Archive

Member "knot-2.9.2/tests/knot/test_zone-update.c" (12 Dec 2019, 10760 Bytes) of package /linux/misc/dns/knot-2.9.2.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "test_zone-update.c": 2.9.1_vs_2.9.2.

    1 /*  Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
    2 
    3     This program is free software: you can redistribute it and/or modify
    4     it under the terms of the GNU General Public License as published by
    5     the Free Software Foundation, either version 3 of the License, or
    6     (at your option) any later version.
    7 
    8     This program is distributed in the hope that it will be useful,
    9     but WITHOUT ANY WARRANTY; without even the implied warranty of
   10     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   11     GNU General Public License for more details.
   12 
   13     You should have received a copy of the GNU General Public License
   14     along with this program.  If not, see <https://www.gnu.org/licenses/>.
   15  */
   16 
   17 #include <assert.h>
   18 #include <pthread.h>
   19 #include <tap/basic.h>
   20 #include <tap/files.h>
   21 #include <unistd.h>
   22 
   23 #include "test_conf.h"
   24 #include "contrib/macros.h"
   25 #include "contrib/getline.h"
   26 #include "knot/updates/zone-update.h"
   27 #include "knot/zone/adjust.h"
   28 #include "knot/zone/node.h"
   29 #include "libzscanner/scanner.h"
   30 #include "knot/server/server.h"
   31 
   32 static const char *zone_str1 = "test. 600 IN SOA ns.test. m.test. 1 900 300 4800 900 \n";
   33 static const char *zone_str2 = "test. 600 IN TXT \"test\"\n";
   34 static const char *add_str   = "test. 600 IN TXT \"test2\"\n";
   35 static const char *del_str   = "test. 600 IN TXT \"test\"\n";
   36 static const char *node_str1 = "node.test. 601 IN TXT \"abc\"\n";
   37 static const char *node_str2 = "node.test. 601 IN TXT \"def\"\n";
   38 
   39 knot_rrset_t rrset;
   40 
   41 /*!< \brief Returns true if node contains given RR in its RRSets. */
   42 static bool node_contains_rr(const zone_node_t *node, const knot_rrset_t *data)
   43 {
   44     const knot_rdataset_t *zone_rrs = node_rdataset(node, data->type);
   45     if (zone_rrs != NULL) {
   46         knot_rdata_t *rr = data->rrs.rdata;
   47         for (size_t i = 0; i < data->rrs.count; ++i) {
   48             if (!knot_rdataset_member(zone_rrs, rr)) {
   49                 return false;
   50             }
   51             rr = knot_rdataset_next(rr);
   52         }
   53 
   54         return true;
   55     } else {
   56         return false;
   57     }
   58 }
   59 
   60 static void process_rr(zs_scanner_t *scanner)
   61 {
   62     knot_rrset_init(&rrset, scanner->r_owner, scanner->r_type, scanner->r_class,
   63                     scanner->r_ttl);
   64 
   65     int ret = knot_rrset_add_rdata(&rrset, scanner->r_data,
   66                                    scanner->r_data_length, NULL);
   67     (void)ret;
   68     assert(ret == KNOT_EOK);
   69 }
   70 
   71 static int rr_data_cmp(struct rr_data *a, struct rr_data *b)
   72 {
   73     if (a->type != b->type) {
   74         return 1;
   75     }
   76     if (a->ttl != b->ttl) {
   77         return 1;
   78     }
   79     if (a->rrs.count != b->rrs.count) {
   80         return 1;
   81     }
   82     if (a->rrs.rdata != b->rrs.rdata) {
   83         return 1;
   84     }
   85     if (a->additional != b->additional) {
   86         return 1;
   87     }
   88     return 0;
   89 }
   90 
   91 static int test_node_unified(zone_node_t *n1, void *v)
   92 {
   93     UNUSED(v);
   94     zone_node_t *n2 = binode_node(n1, false);
   95     if (n2 == n1) {
   96         n2 = binode_node(n1, true);
   97     }
   98     ok(n1->owner == n2->owner, "binode %s has equal %s owner", n1->owner, n2->owner);
   99     ok(n1->rrset_count == n2->rrset_count, "binode %s has equal rrset_count", n1->owner);
  100     for (uint16_t i = 0; i < n1->rrset_count; i++) {
  101         ok(rr_data_cmp(&n1->rrs[i], &n2->rrs[i]) == 0, "binode %s has equal rrs", n1->owner);
  102     }
  103     if (n1->flags & NODE_FLAGS_BINODE) {
  104         ok((n1->flags ^ n2->flags) == NODE_FLAGS_SECOND, "binode %s has correct flags", n1->owner);
  105     }
  106     ok(n1->children == n2->children, "binode %s has equal children count", n1->owner);
  107     return KNOT_EOK;
  108 }
  109 
  110 static void test_zone_unified(zone_t *z)
  111 {
  112     knot_sem_wait(&z->cow_lock);
  113     zone_tree_apply(z->contents->nodes, test_node_unified, NULL);
  114     knot_sem_post(&z->cow_lock);
  115 }
  116 
  117 void test_full(zone_t *zone, zs_scanner_t *sc)
  118 {
  119     zone_update_t update;
  120     /* Init update */
  121     int ret = zone_update_init(&update, zone, UPDATE_FULL);
  122     is_int(KNOT_EOK, ret, "zone update: init full");
  123 
  124     if (zs_set_input_string(sc, zone_str1, strlen(zone_str1)) != 0 ||
  125         zs_parse_all(sc) != 0) {
  126         assert(0);
  127     }
  128 
  129     /* First addition */
  130     ret = zone_update_add(&update, &rrset);
  131     knot_rdataset_clear(&rrset.rrs, NULL);
  132     is_int(KNOT_EOK, ret, "full zone update: first addition");
  133 
  134     if (zs_set_input_string(sc, zone_str2, strlen(zone_str2)) != 0 ||
  135         zs_parse_all(sc) != 0) {
  136         assert(0);
  137     }
  138 
  139     /* Second addition */
  140     ret = zone_update_add(&update, &rrset);
  141     zone_node_t *node = (zone_node_t *) zone_update_get_node(&update, rrset.owner);
  142     bool rrset_present = node_contains_rr(node, &rrset);
  143     ok(ret == KNOT_EOK && rrset_present, "full zone update: second addition");
  144 
  145     /* Removal */
  146     ret = zone_update_remove(&update, &rrset);
  147     node = (zone_node_t *) zone_update_get_node(&update, rrset.owner);
  148     rrset_present = node_contains_rr(node, &rrset);
  149     ok(ret == KNOT_EOK && !rrset_present, "full zone update: removal");
  150 
  151     /* Last addition */
  152     ret = zone_update_add(&update, &rrset);
  153     node = (zone_node_t *) zone_update_get_node(&update, rrset.owner);
  154     rrset_present = node_contains_rr(node, &rrset);
  155     ok(ret == KNOT_EOK && rrset_present, "full zone update: last addition");
  156 
  157     knot_rdataset_clear(&rrset.rrs, NULL);
  158 
  159     /* Prepare node removal */
  160     if (zs_set_input_string(sc, node_str1, strlen(node_str1)) != 0 ||
  161         zs_parse_all(sc) != 0) {
  162         assert(0);
  163     }
  164     ret = zone_update_add(&update, &rrset);
  165     assert(ret == KNOT_EOK);
  166     knot_rdataset_clear(&rrset.rrs, NULL);
  167 
  168     if (zs_set_input_string(sc, node_str2, strlen(node_str2)) != 0 ||
  169         zs_parse_all(sc) != 0) {
  170         assert(0);
  171     }
  172     ret = zone_update_add(&update, &rrset);
  173     assert(ret == KNOT_EOK);
  174     knot_rdataset_clear(&rrset.rrs, NULL);
  175     knot_dname_t *rem_node_name = knot_dname_from_str_alloc("node.test");
  176     node = (zone_node_t *) zone_update_get_node(&update, rem_node_name);
  177     assert(node && node_rdataset(node, KNOT_RRTYPE_TXT)->count == 2);
  178     /* Node removal */
  179     ret = zone_update_remove_node(&update, rem_node_name);
  180     node = (zone_node_t *) zone_update_get_node(&update, rem_node_name);
  181     ok(ret == KNOT_EOK && !node, "full zone update: node removal");
  182     knot_dname_free(rem_node_name, NULL);
  183 
  184     /* Re-add a node for later incremental functionality test */
  185     if (zs_set_input_string(sc, node_str1, strlen(node_str1)) != 0 ||
  186         zs_parse_all(sc) != 0) {
  187         assert(0);
  188     }
  189     ret = zone_update_add(&update, &rrset);
  190     assert(ret == KNOT_EOK);
  191     knot_rdataset_clear(&rrset.rrs, NULL);
  192 
  193     /* Commit */
  194     ret = zone_update_commit(conf(), &update);
  195     node = zone_contents_find_node_for_rr(zone->contents, &rrset);
  196     rrset_present = node_contains_rr(node, &rrset);
  197     ok(ret == KNOT_EOK && rrset_present, "full zone update: commit (max TTL: %u)", zone->contents->max_ttl);
  198 
  199     test_zone_unified(zone);
  200 
  201     knot_rdataset_clear(&rrset.rrs, NULL);
  202 }
  203 
  204 void test_incremental(zone_t *zone, zs_scanner_t *sc)
  205 {
  206     int ret = KNOT_EOK;
  207 
  208     /* Init update */
  209     zone_update_t update;
  210     zone_update_init(&update, zone, UPDATE_INCREMENTAL);
  211     ok(update.zone == zone && changeset_empty(&update.change),
  212        "incremental zone update: init");
  213 
  214     if (zs_set_input_string(sc, add_str, strlen(add_str)) != 0 ||
  215         zs_parse_all(sc) != 0) {
  216         assert(0);
  217     }
  218 
  219     /* Addition */
  220     ret = zone_update_add(&update, &rrset);
  221     knot_rdataset_clear(&rrset.rrs, NULL);
  222     is_int(KNOT_EOK, ret, "incremental zone update: addition");
  223 
  224     const zone_node_t *synth_node = update.new_cont->apex;
  225     ok(synth_node && node_rdataset(synth_node, KNOT_RRTYPE_TXT)->count == 2,
  226        "incremental zone update: add change");
  227 
  228     if (zs_set_input_string(sc, del_str, strlen(del_str)) != 0 ||
  229         zs_parse_all(sc) != 0) {
  230         assert(0);
  231     }
  232     /* Removal */
  233     ret = zone_update_remove(&update, &rrset);
  234     is_int(KNOT_EOK, ret, "incremental zone update: removal");
  235     knot_rdataset_clear(&rrset.rrs, NULL);
  236 
  237     ok(node_rdataset(synth_node, KNOT_RRTYPE_TXT)->count == 1,
  238        "incremental zone update: del change");
  239 
  240     /* Prepare node removal */
  241     if (zs_set_input_string(sc, node_str2, strlen(node_str2)) != 0 ||
  242         zs_parse_all(sc) != 0) {
  243         assert(0);
  244     }
  245     ret = zone_update_add(&update, &rrset);
  246     assert(ret == KNOT_EOK);
  247     knot_rdataset_clear(&rrset.rrs, NULL);
  248 
  249     knot_dname_t *rem_node_name = knot_dname_from_str_alloc("node.test");
  250     synth_node = zone_update_get_node(&update, rem_node_name);
  251     assert(synth_node && node_rdataset(synth_node, KNOT_RRTYPE_TXT)->count == 2);
  252     /* Node Removal */
  253     ret = zone_update_remove_node(&update, rem_node_name);
  254     synth_node = zone_update_get_node(&update, rem_node_name);
  255     ok(ret == KNOT_EOK && !synth_node,
  256        "incremental zone update: node removal");
  257     knot_dname_free(rem_node_name, NULL);
  258 
  259     /* Re-add a node for later incremental functionality test */
  260     if (zs_set_input_string(sc, node_str1, strlen(node_str1)) != 0 ||
  261         zs_parse_all(sc) != 0) {
  262         assert(0);
  263     }
  264     ret = zone_update_add(&update, &rrset);
  265     assert(ret == KNOT_EOK);
  266     knot_rdataset_clear(&rrset.rrs, NULL);
  267 
  268     /* Commit */
  269     ret = zone_update_commit(conf(), &update);
  270     const zone_node_t *iter_node = zone_contents_find_node_for_rr(zone->contents, &rrset);
  271     bool rrset_present = node_contains_rr(iter_node, &rrset);
  272     ok(ret == KNOT_EOK && rrset_present, "incremental zone update: commit");
  273 
  274     test_zone_unified(zone);
  275 
  276     knot_rdataset_clear(&rrset.rrs, NULL);
  277 
  278     size_t zone_size1 = zone->contents->size;
  279     uint32_t zone_max_ttl1 = zone->contents->max_ttl;
  280     ret = zone_adjust_full(zone->contents);
  281     ok(ret == KNOT_EOK, "zone adjust full shall work");
  282     size_t zone_size2 = zone->contents->size;
  283     uint32_t zone_max_ttl2 = zone->contents->max_ttl;
  284     ok(zone_size1 == zone_size2, "zone size measured the same incremental vs full (%zu, %zu)", zone_size1, zone_size2);
  285     ok(zone_max_ttl1 == zone_max_ttl2, "zone max TTL measured the same incremental vs full (%u, %u)", zone_max_ttl1, zone_max_ttl2);
  286     // TODO test more things after re-adjust, search for non-unified bi-nodes
  287 }
  288 
  289 int main(int argc, char *argv[])
  290 {
  291     plan_lazy();
  292 
  293     char *temp_dir = test_mkdtemp();
  294     ok(temp_dir != NULL, "make temporary directory");
  295 
  296     char conf_str[512];
  297     snprintf(conf_str, sizeof(conf_str),
  298              "zone:\n"
  299              " - domain: test.\n"
  300              "template:\n"
  301              " - id: default\n"
  302          "   max-journal-db-size: 100M\n"
  303              "   storage: %s\n",
  304              temp_dir);
  305 
  306     /* Load test configuration. */
  307     int ret = test_conf(conf_str, NULL);
  308     is_int(KNOT_EOK, ret, "load configuration");
  309 
  310     server_t server;
  311     ret = server_init(&server, 1);
  312     is_int(KNOT_EOK, ret, "server init");
  313 
  314     /* Set up empty zone */
  315     knot_dname_t *apex = knot_dname_from_str_alloc("test");
  316     assert(apex);
  317     zone_t *zone = zone_new(apex);
  318     zone->journaldb = &server.journaldb;
  319 
  320     /* Setup zscanner */
  321     zs_scanner_t sc;
  322     if (zs_init(&sc, "test.", KNOT_CLASS_IN, 3600) != 0 ||
  323         zs_set_processing(&sc, process_rr, NULL, NULL) != 0) {
  324         assert(0);
  325     }
  326 
  327     /* Test FULL update, commit it and use the result to test the INCREMENTAL update */
  328     test_full(zone, &sc);
  329     test_incremental(zone, &sc);
  330 
  331     zs_deinit(&sc);
  332     zone_free(&zone);
  333     server_deinit(&server);
  334     knot_dname_free(apex, NULL);
  335     conf_free(conf());
  336     test_rm_rf(temp_dir);
  337     free(temp_dir);
  338 
  339     return 0;
  340 }