Skip to content

Commit 6a71fc4

Browse files
committed
Adding unit tests for framework advanced APIs
1 parent 9b0f7f8 commit 6a71fc4

File tree

2 files changed

+272
-0
lines changed

2 files changed

+272
-0
lines changed

tests/integration_test/BUILD

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,23 @@
1+
cc_test(
2+
name = "test_advanced_api",
3+
srcs = [
4+
"test_advanced_api.cpp"
5+
],
6+
deps = [
7+
"//:corevx",
8+
"@googletest//:gtest_main",
9+
"//targets/ai_server:imported_openvx_ai_server",
10+
"//targets/c_model:imported_openvx_c_model",
11+
"//targets/debug:imported_openvx_debug",
12+
"//targets/extras:imported_openvx_extras",
13+
],
14+
linkopts = select({
15+
"@platforms//os:linux": ["-Wl,-rpath,$ORIGIN"],
16+
"@platforms//os:macos": ["-Wl,-rpath,@executable_path"],
17+
"//conditions:default": [],
18+
}),
19+
size = "small"
20+
)
121

222
cc_test(
323
name = "test_aiserver",
Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
/**
2+
* @file test_advanced+api.cpp
3+
* @brief Test Framework Advanced API
4+
* @version 0.1
5+
* @date 2025-06-26
6+
*
7+
* @copyright Copyright (c) 2025
8+
*
9+
*/
10+
#include <chrono>
11+
#include <filesystem>
12+
#include <fstream>
13+
#include <string>
14+
#include <thread>
15+
#include <vector>
16+
17+
#include <VX/vx.h>
18+
#include <gtest/gtest.h>
19+
20+
#include "vx_internal.h"
21+
22+
class AdvancedIntegrationTest : public ::testing::Test
23+
{
24+
protected:
25+
vx_context context;
26+
vx_graph graph;
27+
28+
// LogCapture struct for custom callback test
29+
struct LogCapture
30+
{
31+
vx_status status = VX_SUCCESS;
32+
std::string message;
33+
static void VX_CALLBACK Callback(vx_context, vx_reference, vx_status status,
34+
const vx_char string[])
35+
{
36+
instance().status = status;
37+
instance().message = string;
38+
}
39+
static LogCapture& instance()
40+
{
41+
static LogCapture inst;
42+
return inst;
43+
}
44+
void reset()
45+
{
46+
status = VX_SUCCESS;
47+
message.clear();
48+
}
49+
};
50+
51+
void SetUp() override
52+
{
53+
// Initialize OpenVX context
54+
context = vxCreateContext();
55+
ASSERT_EQ(vxGetStatus(context), VX_SUCCESS);
56+
}
57+
58+
void TearDown() override
59+
{
60+
vxReleaseGraph(&graph);
61+
vxReleaseContext(&context);
62+
}
63+
64+
public:
65+
// Dummy kernel function and validator for user kernel test
66+
static int dummy_kernel_call_count;
67+
68+
static vx_status VX_CALLBACK DummyKernelFunc(vx_node, const vx_reference*, vx_uint32)
69+
{
70+
++dummy_kernel_call_count;
71+
return VX_SUCCESS;
72+
}
73+
74+
static vx_status VX_CALLBACK DummyKernelValidate(vx_node, const vx_reference[], vx_uint32,
75+
vx_meta_format[])
76+
{
77+
return VX_SUCCESS;
78+
}
79+
80+
static vx_action VX_CALLBACK callback(vx_node node)
81+
{
82+
vx_action action = VX_ACTION_ABANDON;
83+
vx_size expected = 2;
84+
vx_parameter param = vxGetParameterByIndex(node, 1); // copied Value
85+
if (param)
86+
{
87+
vx_scalar scalar = nullptr;
88+
vxQueryParameter(param, VX_PARAMETER_REF, &scalar, sizeof(scalar));
89+
if (scalar)
90+
{
91+
vx_uint8 value = 0u;
92+
vxCopyScalar(scalar, &value, VX_READ_ONLY, VX_MEMORY_TYPE_HOST);
93+
if (value == expected)
94+
{
95+
action = VX_ACTION_CONTINUE;
96+
}
97+
vxReleaseScalar(&scalar);
98+
}
99+
vxReleaseParameter(&param);
100+
}
101+
return action;
102+
}
103+
};
104+
105+
// Define the static member
106+
int AdvancedIntegrationTest::dummy_kernel_call_count = 0;
107+
108+
TEST_F(AdvancedIntegrationTest, TestNodeCallback)
109+
{
110+
vx_size in_count = 2u, out_count = 0;
111+
112+
// Create IOs
113+
vx_scalar input = vxCreateScalar(context, VX_TYPE_SIZE, &in_count);
114+
vx_scalar output = vxCreateScalar(context, VX_TYPE_SIZE, &out_count);
115+
ASSERT_EQ(vxGetStatus(input), VX_SUCCESS);
116+
ASSERT_EQ(vxGetStatus(output), VX_SUCCESS);
117+
118+
// Create graph
119+
graph = vxCreateGraph(context);
120+
ASSERT_EQ(vxGetStatus(graph), VX_SUCCESS);
121+
122+
// Create node
123+
vx_node node = vxCopyNode(graph, (vx_reference)input, (vx_reference)output);
124+
ASSERT_EQ(vxGetStatus(node), VX_SUCCESS);
125+
126+
// Assign callback
127+
ASSERT_EQ(vxAssignNodeCallback(node, &AdvancedIntegrationTest::callback), VX_SUCCESS);
128+
ASSERT_EQ(vxRetrieveNodeCallback(node), &AdvancedIntegrationTest::callback);
129+
130+
// Verify graph
131+
ASSERT_EQ(vxVerifyGraph(graph), VX_SUCCESS);
132+
133+
// Process graph
134+
ASSERT_EQ(vxProcessGraph(graph), VX_SUCCESS);
135+
136+
// Validate results
137+
ASSERT_EQ(vxCopyScalar(output, &out_count, VX_READ_ONLY, VX_MEMORY_TYPE_HOST), VX_SUCCESS);
138+
ASSERT_EQ(in_count, out_count);
139+
140+
// Cleanup
141+
vxReleaseScalar(&input);
142+
vxReleaseScalar(&output);
143+
vxReleaseNode(&node);
144+
}
145+
146+
TEST_F(AdvancedIntegrationTest, TestAddLogEntryWithHelperLogReader)
147+
{
148+
vxRegisterHelperAsLogReader(context);
149+
const char* test_message = "UnitTest log entry: %d";
150+
int test_value = 42;
151+
vxAddLogEntry((vx_reference)context, VX_FAILURE, test_message, test_value);
152+
char log_message[VX_MAX_LOG_MESSAGE_LEN] = {0};
153+
vx_status log_status = vxGetLogEntry((vx_reference)context, log_message);
154+
ASSERT_EQ(log_status, VX_FAILURE);
155+
ASSERT_STREQ(log_message, "UnitTest log entry: 42");
156+
157+
// The log should now be empty
158+
log_status = vxGetLogEntry((vx_reference)context, log_message);
159+
ASSERT_EQ(log_status, VX_SUCCESS);
160+
}
161+
162+
TEST_F(AdvancedIntegrationTest, TestAddLogEntryWithCustomCallback)
163+
{
164+
LogCapture::instance().reset();
165+
vxRegisterLogCallback(context, &LogCapture::Callback, vx_false_e);
166+
const char* test_message = "CustomCallback log entry: %s %d";
167+
const char* word = "value";
168+
int number = 99;
169+
vxAddLogEntry((vx_reference)context, VX_ERROR_INVALID_VALUE, test_message, word, number);
170+
std::this_thread::sleep_for(std::chrono::milliseconds(10));
171+
ASSERT_EQ(LogCapture::instance().status, VX_ERROR_INVALID_VALUE);
172+
ASSERT_EQ(LogCapture::instance().message, "CustomCallback log entry: value 99");
173+
vxRegisterLogCallback(context, nullptr, vx_false_e);
174+
}
175+
176+
TEST_F(AdvancedIntegrationTest, TestDirectiveLoggingAndPerformance)
177+
{
178+
// Enable logging and check that log entries are recorded
179+
ASSERT_EQ(vxDirective((vx_reference)context, VX_DIRECTIVE_ENABLE_LOGGING), VX_SUCCESS);
180+
vxRegisterHelperAsLogReader(context);
181+
vxAddLogEntry((vx_reference)context, VX_FAILURE, "Log should be recorded");
182+
char log_message[VX_MAX_LOG_MESSAGE_LEN] = {0};
183+
vx_status log_status = vxGetLogEntry((vx_reference)context, log_message);
184+
ASSERT_EQ(log_status, VX_FAILURE);
185+
ASSERT_STREQ(log_message, "Log should be recorded");
186+
187+
// Disable logging and check that log entries are not recorded
188+
ASSERT_EQ(vxDirective((vx_reference)context, VX_DIRECTIVE_DISABLE_LOGGING), VX_SUCCESS);
189+
vxAddLogEntry((vx_reference)context, VX_FAILURE, "Log should NOT be recorded");
190+
log_status = vxGetLogEntry((vx_reference)context, log_message);
191+
ASSERT_EQ(log_status, VX_SUCCESS); // No new log entry
192+
193+
// Enable/disable performance (should be supported for context)
194+
ASSERT_EQ(vxDirective((vx_reference)context, VX_DIRECTIVE_ENABLE_PERFORMANCE), VX_SUCCESS);
195+
ASSERT_EQ(vxDirective((vx_reference)context, VX_DIRECTIVE_DISABLE_PERFORMANCE), VX_SUCCESS);
196+
197+
// Try a directive not supported for this reference type (e.g., performance on a scalar)
198+
vx_scalar scalar = vxCreateScalar(context, VX_TYPE_INT32, nullptr);
199+
ASSERT_EQ(vxDirective((vx_reference)scalar, VX_DIRECTIVE_ENABLE_PERFORMANCE),
200+
VX_ERROR_NOT_SUPPORTED);
201+
vxReleaseScalar(&scalar);
202+
}
203+
204+
TEST_F(AdvancedIntegrationTest, TestAddUserKernelLifecycle)
205+
{
206+
AdvancedIntegrationTest::dummy_kernel_call_count = 0;
207+
const char* kernel_name = "org.khronos.unittest.dummy";
208+
vx_enum kernel_enum = 0;
209+
ASSERT_EQ(vxAllocateUserKernelId(context, &kernel_enum), VX_SUCCESS);
210+
vx_kernel kernel = vxAddUserKernel(
211+
context, kernel_name, kernel_enum, &AdvancedIntegrationTest::DummyKernelFunc, 1,
212+
&AdvancedIntegrationTest::DummyKernelValidate, nullptr, nullptr);
213+
ASSERT_NE(kernel, nullptr);
214+
ASSERT_EQ(vxGetStatus((vx_reference)kernel), VX_SUCCESS);
215+
216+
// Add a parameter (required before finalizing)
217+
ASSERT_EQ(
218+
vxAddParameterToKernel(kernel, 0, VX_INPUT, VX_TYPE_UINT8, VX_PARAMETER_STATE_REQUIRED),
219+
VX_SUCCESS);
220+
221+
// Finalize the kernel
222+
ASSERT_EQ(vxFinalizeKernel(kernel), VX_SUCCESS);
223+
224+
// Kernel should be retrievable by name
225+
vx_kernel found = vxGetKernelByName(context, kernel_name);
226+
ASSERT_EQ(found, kernel);
227+
228+
// Create a real graph and scalar parameter
229+
vx_graph graph = vxCreateGraph(context);
230+
ASSERT_EQ(vxGetStatus((vx_reference)graph), VX_SUCCESS);
231+
vx_uint8 scalar_value = 123;
232+
vx_scalar scalar = vxCreateScalar(context, VX_TYPE_UINT8, &scalar_value);
233+
ASSERT_EQ(vxGetStatus((vx_reference)scalar), VX_SUCCESS);
234+
235+
// Add a node using the user kernel and the scalar as input
236+
vx_node node = vxCreateGenericNode(graph, kernel);
237+
ASSERT_NE(node, nullptr);
238+
ASSERT_EQ(vxGetStatus((vx_reference)node), VX_SUCCESS);
239+
ASSERT_EQ(vxSetParameterByIndex(node, 0, (vx_reference)scalar), VX_SUCCESS);
240+
241+
// Verify and process the graph
242+
ASSERT_EQ(vxVerifyGraph(graph), VX_SUCCESS);
243+
ASSERT_EQ(vxProcessGraph(graph), VX_SUCCESS);
244+
ASSERT_EQ(AdvancedIntegrationTest::dummy_kernel_call_count, 1);
245+
246+
// Cleanup
247+
vxReleaseNode(&node);
248+
vxReleaseScalar(&scalar);
249+
vxReleaseGraph(&graph);
250+
ASSERT_EQ(vxRemoveKernel(kernel), VX_SUCCESS);
251+
ASSERT_EQ(vxReleaseKernel(&kernel), VX_SUCCESS);
252+
}

0 commit comments

Comments
 (0)