[PATCH v2 03/23] nscd: Enhance tst-nscd-basic with query counters
Florian Weimer
fweimer@redhat.com
Fri Mar 20 20:41:25 GMT 2026
This helps to test that the cache is actually used.
---
nscd/tst-nscd-basic.c | 58 ++++++++++++++++++++++++++++++++++++++++++
support/nscd_test.h | 4 +++
support/support_nscd.c | 33 ++++++++++++++++++++++++
3 files changed, 95 insertions(+)
diff --git a/nscd/tst-nscd-basic.c b/nscd/tst-nscd-basic.c
index 2ce1fece60..3dfde92c36 100644
--- a/nscd/tst-nscd-basic.c
+++ b/nscd/tst-nscd-basic.c
@@ -31,6 +31,8 @@
#include <support/xmemstream.h>
#include <support/xstdio.h>
+#include <nscd/nscd-statdata.h>
+
/* Large GECOS string for the large-gecos user. */
static char *large_gecos;
@@ -452,17 +454,73 @@ do_test (void)
/* First run the tests without nscd running, to check that the test
expectations are correct. Use a separate process to avoid
caching nscd availability. */
+ puts ("info: testing without nscd");
support_isolate_in_subprocess (all_tests, NULL);
support_nscd_copy_configuration ();
support_nscd_start ();
+ /* Initially the query counters are all zero. */
+ {
+ struct statdata stat;
+ support_nscd_get_statistics (&stat);
+ for (int i = 0; i < lastdb; ++i)
+ {
+ TEST_COMPARE (stat.dbs[i].nentries, 0);
+ TEST_COMPARE (stat.dbs[i].poshit, 0);
+ TEST_COMPARE (stat.dbs[i].neghit, 0);
+ TEST_COMPARE (stat.dbs[i].posmiss, 0);
+ TEST_COMPARE (stat.dbs[i].negmiss, 0);
+ }
+ }
+
+ puts ("info: first pass with nscd");
all_tests (NULL);
+ /* After running the tests, we have cache entries in all databases.
+ The counters have been empirically determined. They mostly check
+ that nscd is actually used. */
+ struct statdata stat_first_pass;
+ support_nscd_get_statistics (&stat_first_pass);
+ TEST_COMPARE (stat_first_pass.dbs[pwddb].nentries, 10);
+ TEST_COMPARE (stat_first_pass.dbs[pwddb].posmiss, 4);
+ TEST_COMPARE (stat_first_pass.dbs[pwddb].negmiss, 2);
+ TEST_COMPARE (stat_first_pass.dbs[grpdb].nentries, 10);
+ TEST_COMPARE (stat_first_pass.dbs[grpdb].posmiss, 5);
+ TEST_COMPARE (stat_first_pass.dbs[grpdb].negmiss, 2);
+ TEST_COMPARE (stat_first_pass.dbs[hstdb].nentries, 5);
+ TEST_COMPARE (stat_first_pass.dbs[hstdb].posmiss, 5);
+ TEST_COMPARE (stat_first_pass.dbs[hstdb].negmiss, 0);
+ TEST_COMPARE (stat_first_pass.dbs[netgrdb].nentries, 25);
+ TEST_COMPARE (stat_first_pass.dbs[netgrdb].posmiss, 25);
+ TEST_COMPARE (stat_first_pass.dbs[netgrdb].negmiss, 0);
+ TEST_COMPARE (stat_first_pass.dbs[servdb].nentries, 5);
+ TEST_COMPARE (stat_first_pass.dbs[servdb].posmiss, 3);
+ TEST_COMPARE (stat_first_pass.dbs[servdb].negmiss, 2);
+
/* Retry from cache. */
+ puts ("info: second pass with nscd, with caching");
all_tests (NULL);
+ /* Retries should have used the cache and not increment the query
+ counters. This means that the shared mapping is used, not the
+ socket query interface or the in-process nss_files service
+ module. */
+ {
+ struct statdata stat;
+ support_nscd_get_statistics (&stat);
+ for (int i = 0; i < lastdb; ++i)
+ {
+ TEST_COMPARE (stat.dbs[i].nentries, stat_first_pass.dbs[i].nentries);
+ TEST_COMPARE (stat.dbs[i].poshit, stat_first_pass.dbs[i].poshit);
+ TEST_COMPARE (stat.dbs[i].neghit, stat_first_pass.dbs[i].neghit);
+ TEST_COMPARE (stat.dbs[i].posmiss, stat_first_pass.dbs[i].posmiss);
+ TEST_COMPARE (stat.dbs[i].negmiss, stat_first_pass.dbs[i].negmiss);
+ }
+ }
+
+ puts ("info: pass with interleaved invalidation");
invalidate = support_nscd_invalidate;
all_tests (NULL);
diff --git a/support/nscd_test.h b/support/nscd_test.h
index 60208098f4..95d9c1cd38 100644
--- a/support/nscd_test.h
+++ b/support/nscd_test.h
@@ -36,4 +36,8 @@ void support_nscd_stop (void);
services). */
void support_nscd_invalidate (const char *database);
+/* Fill in *STATS with data from the running nscd daemon. */
+struct statdata;
+void support_nscd_get_statistics (struct statdata *stat);
+
#endif /* SUPPORT_NSCD_TEST_H */
diff --git a/support/support_nscd.c b/support/support_nscd.c
index 2d7d503ad6..96d1e6b874 100644
--- a/support/support_nscd.c
+++ b/support/support_nscd.c
@@ -18,20 +18,25 @@
#include <support/nscd_test.h>
+#include <errno.h>
#include <libgen.h>
#include <signal.h>
#include <spawn.h>
#include <stdbool.h>
+#include <stdio.h>
#include <stdlib.h>
#include <support/check.h>
#include <support/support.h>
#include <support/xspawn.h>
#include <support/xunistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
#include <sys/wait.h>
#include <unistd.h>
#include <nscd/nscd.h>
#include <nscd/nscd-client.h>
+#include <nscd/nscd-statdata.h>
static pid_t nscd_pid;
@@ -113,3 +118,31 @@ support_nscd_invalidate (const char *database)
TEST_COMPARE (system (cmd), 0);
free (cmd);
}
+
+void
+support_nscd_get_statistics (struct statdata *stat)
+{
+ struct sockaddr_un sun;
+ sun.sun_family = AF_UNIX;
+ strcpy (sun.sun_path, _PATH_NSCDSOCKET);
+
+ int sock = socket (PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ if (sock < 0 || connect (sock, (struct sockaddr *) &sun, sizeof (sun)) < 0)
+ FAIL_EXIT1 ("failed to open nscd socket: %m");
+
+ request_header req;
+ req.version = NSCD_VERSION;
+ req.type = GETSTAT;
+ req.key_len = 0;
+
+ if (TEMP_FAILURE_RETRY (send (sock, &req, sizeof (req), MSG_NOSIGNAL))
+ != sizeof (req))
+ FAIL_EXIT1 ("failed to send request to nscd: %m");
+
+ ssize_t ret = TEMP_FAILURE_RETRY (recv (sock, stat, sizeof (*stat), 0));
+
+ errno = EMSGSIZE;
+ if (ret != sizeof (*stat) || stat->version != STATDATA_VERSION_FULL)
+ FAIL_EXIT1 ("failed to receive statistics from nscd: %m");
+ close (sock);
+}
--
2.53.0
More information about the Libc-alpha
mailing list