svn commit: r1936966 - in apr/apr/trunk: memcache test

[email protected]
Newsgroups gmane.comp.apache.apr.cvs
Message-ID <178610863101.3573758.10803074093609200536@svn03-he-fi>
Author: covener
Date: Fri Aug  7 13:17:10 2026
New Revision: 1936966

Log:
fix memcache version processing

Modified:
   apr/apr/trunk/memcache/apr_memcache.c
   apr/apr/trunk/test/memcachedmock.c
   apr/apr/trunk/test/testmemcache.c

Modified: apr/apr/trunk/memcache/apr_memcache.c
==============================================================================
--- apr/apr/trunk/memcache/apr_memcache.c	Fri Aug  7 13:16:45 2026	(r1936965)
+++ apr/apr/trunk/memcache/apr_memcache.c	Fri Aug  7 13:17:10 2026	(r1936966)
@@ -1174,12 +1174,12 @@ apr_memcache_version(apr_memcache_server
     }
 
     if (strncmp(MS_VERSION, conn->buffer, MS_VERSION_LEN) == 0) {
-        if (conn->blen < MS_VERSION_LEN + 2) {
+        if (conn->blen < MS_VERSION_LEN + 4) {
             rv = APR_EGENERAL;
         }
         else {
             *baton = apr_pstrmemdup(p, conn->buffer+MS_VERSION_LEN+1,
-                                    conn->blen - MS_VERSION_LEN - 2);
+                                    conn->blen - MS_VERSION_LEN - 3);
             rv = APR_SUCCESS;
         }
     }

Modified: apr/apr/trunk/test/memcachedmock.c
==============================================================================
--- apr/apr/trunk/test/memcachedmock.c	Fri Aug  7 13:16:45 2026	(r1936965)
+++ apr/apr/trunk/test/memcachedmock.c	Fri Aug  7 13:17:10 2026	(r1936966)
@@ -20,7 +20,15 @@
 #include "apr_pools.h"
 #include "testmemcache.h"
 
-#define MOCK_REPLY "VERSION 1.5.22\r\n"
+#define MOCK_REPLY_DEFAULT "VERSION 1.5.22\r\n"
+
+/* Number of connections to serve before exiting.
+ * The test_connection_validation test needs 2 (one intentional, one
+ * after the server closes the socket).  The version-response tests
+ * need only 1 each.  Pass MOCK_NCONN on the command line after the
+ * reply string to override; default is 2 for backward compatibility.
+ */
+#define MOCK_NCONN_DEFAULT 2
 
 int main(int argc, char *argv[])
 {
@@ -30,7 +38,11 @@ int main(int argc, char *argv[])
     apr_socket_t *server_connection;
     apr_status_t rv;
     apr_size_t length;
-    int i;
+    int i, nconn, conn;
+    const char *reply;
+
+    reply = (argc >= 2) ? argv[1] : MOCK_REPLY_DEFAULT;
+    nconn = (argc >= 3) ? atoi(argv[2]) : MOCK_NCONN_DEFAULT;
 
     apr_initialize();
     atexit(apr_terminate);
@@ -48,37 +60,23 @@ int main(int argc, char *argv[])
 
     apr_socket_listen(server, 5);
 
-    /* Do spin instead of a proper poll for sake of simplicity */
-    for (i = 0; i < 4; i++) {
+    for (conn = 0; conn < nconn; conn++) {
+        /* Do spin instead of a proper poll for sake of simplicity */
+        for (i = 0; i < 4; i++) {
+
+            rv = apr_socket_accept(&server_connection, server, p);
+            if (rv == APR_SUCCESS) {
+                break;
+            }
 
-        rv = apr_socket_accept(&server_connection, server, p);
-        if (rv == APR_SUCCESS) {
-            break;
+            apr_sleep(apr_time_from_sec(1));
         }
 
-        apr_sleep(apr_time_from_sec(1));
-    }
-
-    length = strlen(MOCK_REPLY);
-    apr_socket_send(server_connection, MOCK_REPLY, &length);
-
-    apr_socket_close(server_connection);
+        length = strlen(reply);
+        apr_socket_send(server_connection, reply, &length);
 
-    /* Do spin instead of a proper poll for sake of simplicity */
-    for (i = 0; i < 4; i++) {
-
-        rv = apr_socket_accept(&server_connection, server, p);
-        if (rv == APR_SUCCESS) {
-            break;
-        }
-
-        apr_sleep(apr_time_from_sec(1));
+        apr_socket_close(server_connection);
     }
 
-    length = strlen(MOCK_REPLY);
-    apr_socket_send(server_connection, MOCK_REPLY, &length);
-
-    apr_socket_close(server_connection);
-
     exit(0);
 }

Modified: apr/apr/trunk/test/testmemcache.c
==============================================================================
--- apr/apr/trunk/test/testmemcache.c	Fri Aug  7 13:16:45 2026	(r1936965)
+++ apr/apr/trunk/test/testmemcache.c	Fri Aug  7 13:17:10 2026	(r1936966)
@@ -749,6 +749,110 @@ static void test_connection_validation(a
     apr_proc_wait(&proc, &exitcode, &why, APR_WAIT);
 }
 
+/*
+ * Helper: spawn memcachedmock with a specific reply string (and nconn=1),
+ * call apr_memcache_version(), return the status and (on success) the
+ * version string.  Waits for the mock to finish before returning.
+ */
+static apr_status_t run_mock_version(abts_case *tc, const char *reply,
+                                     char **result_out)
+{
+    apr_procattr_t *procattr;
+    apr_proc_t proc;
+    apr_status_t rv;
+    apr_memcache_t *memcache;
+    apr_memcache_server_t *memserver;
+    char *result = NULL;
+    const char *args[4];
+    int exitcode;
+    apr_exit_why_e why;
+
+    rv = apr_procattr_create(&procattr, p);
+    ABTS_ASSERT(tc, "Couldn't create procattr", rv == APR_SUCCESS);
+    rv = apr_procattr_io_set(procattr, APR_NO_PIPE, APR_NO_PIPE, APR_NO_PIPE);
+    ABTS_ASSERT(tc, "Couldn't set io in procattr", rv == APR_SUCCESS);
+    rv = apr_procattr_error_check_set(procattr, 1);
+    ABTS_ASSERT(tc, "Couldn't set error check in procattr", rv == APR_SUCCESS);
+    rv = apr_procattr_cmdtype_set(procattr, APR_PROGRAM_ENV);
+    ABTS_ASSERT(tc, "Couldn't set copy environment", rv == APR_SUCCESS);
+
+    /* argv: memcachedmock <reply> 1   (serve exactly one connection) */
+    args[0] = "memcachedmock" EXTENSION;
+    args[1] = reply;
+    args[2] = "1";
+    args[3] = NULL;
+    rv = apr_proc_create(&proc, TESTBINPATH "memcachedmock" EXTENSION,
+                         args, NULL, procattr, p);
+    if (APR_SUCCESS != rv) {
+        return APR_ENOTIMPL; /* signal skip to caller */
+    }
+
+    apr_sleep(apr_time_from_sec(2));
+
+    rv = apr_memcache_create(p, 1, 0, &memcache);
+    ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS);
+    rv = apr_memcache_server_create(p, MOCK_HOST, MOCK_PORT, 0, 1, 1,
+                                    apr_time_from_sec(60), &memserver);
+    ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS);
+    rv = apr_memcache_add_server(memcache, memserver);
+    ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS);
+
+    rv = apr_memcache_version(memserver, p, &result);
+
+    apr_proc_wait(&proc, &exitcode, &why, APR_WAIT);
+
+    if (result_out) {
+        *result_out = result;
+    }
+    return rv;
+}
+
+/*
+ * Test how apr_memcache_version() handles well-formed and malformed
+ * VERSION responses from the server.
+ */
+static void test_version_responses(abts_case *tc, void *data)
+{
+    apr_status_t rv;
+    char *result;
+
+    /* --- good response ------------------------------------------------ */
+    abts_log_message("version test: sending 'VERSION 1.5.22\\r\\n', expecting APR_SUCCESS");
+    rv = run_mock_version(tc, "VERSION 1.5.22\r\n", &result);
+    if (rv == APR_ENOTIMPL) {
+        ABTS_SKIP(tc, data, TESTBINPATH "memcachedmock" EXTENSION " could not be executed, skipped");
+        return;
+    }
+    abts_log_message("version test: rv=%d result='%s'", rv, result ? result : "(null)");
+    ABTS_ASSERT(tc, "good VERSION should succeed", rv == APR_SUCCESS);
+    ABTS_STR_EQUAL(tc, "1.5.22", result);
+
+    /* --- empty version string: "VERSION \r\n" ------------------------- */
+    abts_log_message("version test: sending 'VERSION \\r\\n' (empty version), expecting EGENERAL");
+    rv = run_mock_version(tc, "VERSION \r\n", &result);
+    abts_log_message("version test: rv=%d (expected non-zero)", rv);
+    ABTS_ASSERT(tc, "empty version string should fail", rv != APR_SUCCESS);
+
+    /* --- no space after VERSION: "VERSION\r\n" ------------------------ */
+    abts_log_message("version test: sending 'VERSION\\r\\n' (no space), expecting EGENERAL");
+    rv = run_mock_version(tc, "VERSION\r\n", &result);
+    abts_log_message("version test: rv=%d (expected non-zero)", rv);
+    ABTS_ASSERT(tc, "missing space should fail", rv != APR_SUCCESS);
+
+    /* --- completely wrong prefix -------------------------------------- */
+    abts_log_message("version test: sending 'ERROR\\r\\n' (wrong prefix), expecting EGENERAL");
+    rv = run_mock_version(tc, "ERROR\r\n", &result);
+    abts_log_message("version test: rv=%d (expected non-zero)", rv);
+    ABTS_ASSERT(tc, "wrong prefix should fail", rv != APR_SUCCESS);
+
+    /* --- single-character version: shortest valid response ------------ */
+    abts_log_message("version test: sending 'VERSION 1\\r\\n' (single char version), expecting APR_SUCCESS");
+    rv = run_mock_version(tc, "VERSION 1\r\n", &result);
+    abts_log_message("version test: rv=%d result='%s'", rv, result ? result : "(null)");
+    ABTS_ASSERT(tc, "single-char VERSION should succeed", rv == APR_SUCCESS);
+    ABTS_STR_EQUAL(tc, "1", result);
+}
+
 abts_suite *testmemcache(abts_suite * suite)
 {
     suite = ADD_SUITE(suite);
@@ -760,6 +864,7 @@ abts_suite *testmemcache(abts_suite * su
     abts_run_test(suite, test_memcache_addreplace, NULL);
     abts_run_test(suite, test_memcache_incrdecr, NULL);
     abts_run_test(suite, test_connection_validation, NULL);
+    abts_run_test(suite, test_version_responses, NULL);
 
     return suite;
 }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.