resolved: tests for dns_query_go() -- with and without network link
authorJames Coglan <james@neighbourhood.ie>
Fri, 21 Jun 2024 14:40:20 +0000 (15:40 +0100)
committerJames Coglan <james@neighbourhood.ie>
Tue, 23 Jul 2024 13:17:23 +0000 (14:17 +0100)
src/resolve/test-dns-query.c

index 0f917a3e455e5d74252a79aa553e246255f137aa..4f6d70f1c1f642f76ca0140c3853a0144f7c0b17 100644 (file)
@@ -3,6 +3,9 @@
 #include "log.h"
 #include "resolved-dns-query.h"
 #include "resolved-dns-rr.h"
+#include "resolved-dns-scope.h"
+#include "resolved-dns-server.h"
+#include "resolved-link.h"
 #include "resolved-manager.h"
 #include "tests.h"
 
@@ -614,4 +617,103 @@ TEST(dns_query_process_cname_many_success_match_multiple_cname) {
         dns_resource_key_unref(key);
 }
 
+/* ================================================================
+ * dns_query_go()
+ * ================================================================ */
+
+/* Testing this function is somewhat problematic since, in addition to setting up the state for query
+ * candidates, their scopes and transactions, it also directly initiates I/O to files and the network. In
+ * particular:
+ *
+ * - The very first thing it does is try to respond to the query by reading the system /etc/hosts file, which
+ *   may be symlinked to a SystemD resource. Ideally we could test this without accessing global files.
+ *
+ * - dns_scope_get_dns_server() calls manager_get_dns_server(), which tries to read /etc/resolv.conf.
+ *
+ * - A potential solution to these issues would be to let these file paths be configured instead of
+ *   hard-coded into the source.
+ *
+ * - dns_scope_good_domain(), by checking dns_scope_get_dns_server(), will not match with a scope that does
+ *   not have a server configured, either on the scope's link (if it has one) or the manager's main/fallback
+ *   server. Configuring a server means that dns_query_candidate_go() and then dns_transaction_go() will send
+ *   UDP/TCP traffic to that server. Ideally we'd like to test that we can set up all the candidate and
+ *   transaction state without actually causing any requests to be sent.
+ */
+
+static void dns_scope_freep(DnsScope **s) {
+        dns_scope_free(*s);
+}
+
+typedef struct GoConfig {
+        bool use_link;
+} GoConfig;
+
+static GoConfig mk_go_config(void) {
+        return (GoConfig) {
+                .use_link = false
+        };
+}
+
+static void exercise_dns_query_go(GoConfig *cfg) {
+        Manager manager = {};
+        Link *link = NULL;
+        _cleanup_(dns_server_unrefp) DnsServer *server = NULL;
+        _cleanup_(dns_scope_freep) DnsScope *scope = NULL;
+
+        _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
+        _cleanup_(dns_query_freep) DnsQuery *query = NULL;
+
+        DnsProtocol protocol = DNS_PROTOCOL_DNS;
+        int family = AF_INET;
+        int flags = SD_RESOLVED_FLAGS_MAKE(protocol, family, false, false);
+        int ifindex;
+
+        union in_addr_union server_addr = { .in.s_addr = htobe32(0x7f000001) };
+        const char *server_name = "localhost";
+        uint16_t port = 53;
+        DnsServerType type;
+
+        if (cfg->use_link) {
+                ifindex = 1;
+                ASSERT_OK(link_new(&manager, &link, ifindex));
+                ASSERT_NOT_NULL(link);
+                type = DNS_SERVER_LINK;
+        } else {
+                ifindex = 0;
+                link = NULL;
+                type = DNS_SERVER_FALLBACK;
+        }
+
+        ASSERT_OK(sd_event_new(&manager.event));
+        ASSERT_NOT_NULL(manager.event);
+
+        ASSERT_OK(dns_server_new(&manager, &server, type, link, family, &server_addr,
+                        port, ifindex, server_name, RESOLVE_CONFIG_SOURCE_DBUS));
+
+        ASSERT_NOT_NULL(server);
+
+        ASSERT_OK(dns_scope_new(&manager, &scope, link, protocol, family));
+        ASSERT_NOT_NULL(scope);
+
+        ASSERT_OK(dns_question_new_address(&question, AF_INET, "www.example.com", false));
+        ASSERT_NOT_NULL(question);
+
+        ASSERT_OK(dns_query_new(&manager, &query, question, question, NULL, ifindex, flags));
+        ASSERT_NOT_NULL(query);
+
+        ASSERT_OK(dns_query_go(query));
+
+        dns_server_unref(server);
+        sd_event_unref(manager.event);
+}
+
+TEST(dns_query_go) {
+        GoConfig cfg1 = mk_go_config();
+        exercise_dns_query_go(&cfg1);
+
+        GoConfig cfg2 = mk_go_config();
+        cfg2.use_link = true;
+        exercise_dns_query_go(&cfg2);
+}
+
 DEFINE_TEST_MAIN(LOG_DEBUG);