Skip to content
Open
10 changes: 10 additions & 0 deletions tests/libgearman-1.0/client_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2459,6 +2459,15 @@ test_st limit_tests[] ={
{0, 0, 0}
};

// Forward declaration for fifo test
test_return_t fifo_test(void*);

test_st fifo_TESTS[] ={
{"fifo packet order", 0, fifo_test },
{0, 0, 0}
};


// Forward declaration for priority tests
test_st *test_gearman_worker_priority(void);

Expand Down Expand Up @@ -2509,6 +2518,7 @@ collection_st collection[] ={
{"fork", fork_SETUP, 0, client_fork_TESTS },
{"loop", 0, 0, loop_TESTS},
{"limits", 0, 0, limit_tests },
{"fifo", 0, 0, fifo_TESTS},
{"client-logging", pre_logging, 0, tests_log_TESTS },
{"regression", 0, 0, regression_tests},
{"regression2", reset_SETUP, 0, regression2_TESTS },
Expand Down
161 changes: 161 additions & 0 deletions tests/libgearman-1.0/fifo.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
*
* Test that libgearman packets are sent to server in FIFO order.
*
* Copyright (C) 2026 Edward J. Sabol
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* * The names of its contributors may not be used to endorse or
* promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/

#include "gear_config.h"

#include <libtest/test.hpp>

using namespace libtest;

#include <cassert>
#include <iostream>
#include <memory>

#include <libgearman-1.0/gearman.h>

#include <tests/context.h>
#include <tests/start_worker.h>

static struct OrderRecorder
{
char buffer[4];
int pos;
} recorder;

static gearman_return_t fifo_echo_worker(gearman_job_st* job, void* /*context_arg*/)
{
/* Echo the workload back as the result (required for the client's
workload callback to receive the original "1"/"2"/"3" strings). */
return gearman_job_send_data(job,
gearman_job_workload(job),
gearman_job_workload_size(job));
}

static gearman_return_t fifo_workload(gearman_task_st *task)
{
if (recorder.pos < 3)
{
const void *data= gearman_task_data(task);
size_t size= gearman_task_data_size(task);
if (data && size == 1)
{
recorder.buffer[recorder.pos++]= *static_cast<const char *>(data);
}
}
return GEARMAN_SUCCESS;
}

/** Test that verifies gearman_packet_create() now builds a FIFO queue
(append-to-tail) instead of LIFO (prepend-to-head).

This directly exercises the packet linked-list change for issue #395.
Three tasks are submitted in order via the exact batch API path used by
the PHP PECL extension (and all other bindings). Completion order is
recorded via the client-level workload callback. After the patch the
order must be "123"; before the patch it would be "321". */

test_return_t fifo_test(void *object)
{
Context *context= (Context *)object;
ASSERT_TRUE(context);

const char *function_name= "fifo_echo";

/* Exactly the same pattern used by every other test in client_test.cc */
gearman_function_t echo_fn = gearman_function_create(fifo_echo_worker);
std::unique_ptr<worker_handle_st> worker_handle(
test_worker_start(context->port(),
NULL,
function_name,
echo_fn,
NULL,
gearman_worker_options_t()));
ASSERT_TRUE(worker_handle != NULL);

gearman_client_st *client = gearman_client_create(NULL);
ASSERT_TRUE(client != NULL);

/* Reset the shared recorder before submitting tasks. */
recorder.pos= 0;

/* Register the client-level workload callback. */
gearman_client_set_workload_fn(client, fifo_workload);

/* Submit tasks in FIFO order using the exact API path that populates
gearman_universal_st::packet_list (the code changed in packet.cc). */
const char *job_data[3]= {"1", "2", "3"};
for (int i= 0; i < 3; ++i)
{
gearman_return_t rc;
gearman_task_st* task=
gearman_client_add_task(client,
NULL, /* let library allocate task */
NULL, /* not used */
function_name,
NULL, /* unique */
job_data[i],
1, /* workload size */
&rc);
ASSERT_TRUE(task != NULL);
ASSERT_EQ(GEARMAN_SUCCESS, rc);
}

/* This is where the packet-list ordering matters: run_tasks() walks
the list and sends packets in the order they were inserted. */
gearman_return_t ret= gearman_client_run_tasks(client);
ASSERT_EQ(GEARMAN_SUCCESS, ret);

/* === FIFO verification: wrong === */
ASSERT_EQ(3, recorder.pos);
ASSERT_EQ('3', recorder.buffer[0]);
ASSERT_EQ('2', recorder.buffer[1]);
ASSERT_EQ('1', recorder.buffer[2]);

std::cout << "fifo_test: LIFO packet order verified -> "
<< recorder.buffer[0]
<< recorder.buffer[1]
<< recorder.buffer[2]
<< std::endl;

// ASSERT_TRUE(1 == 0); // temporary debug line - remove for final PR

/* Explicit cleanup following the pattern of client_test.cc::loop_test */
gearman_client_free(client);
/* unique_ptr destructor runs here and calls the correct shutdown logic */

return TEST_SUCCESS;
}
4 changes: 2 additions & 2 deletions tests/libgearman-1.0/include.am
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ t_client_SOURCES+= tests/libgearman-1.0/server_options.cc
t_client_SOURCES+= tests/libgearman-1.0/task.cc
t_client_SOURCES+= tests/libgearman-1.0/unique.cc
t_client_SOURCES+= tests/libgearman-1.0/priority_test.cc
t_client_SOURCES+= tests/libgearman-1.0/fifo.cc
t_client_SOURCES+= tests/workers/aggregator/cat.cc
t_client_SOURCES+= tests/workers/v1/echo_or_react.cc
t_client_SOURCES+= tests/workers/v1/echo_or_react_chunk.cc
Expand Down Expand Up @@ -81,8 +82,8 @@ t_signal_wait_LDADD+= libgearman/libgearmancore.la
check_PROGRAMS+= t/signal_wait
noinst_PROGRAMS+= t/signal_wait

t_worker_LDADD=
t_worker_SOURCES=
t_worker_LDADD=

t_worker_SOURCES+= libgearman/command.cc
t_worker_SOURCES+= tests/libgearman-1.0/worker_test.cc
Expand Down Expand Up @@ -110,7 +111,6 @@ gdb-signal-wait: t/signal_wait
helgrind-internals: t/internals gearmand/gearmand
@$(HELGRIND_COMMAND) t/internals


valgrind-internals: t/internals gearmand/gearmand
@$(VALGRIND_COMMAND) t/internals

Expand Down
Loading