Skip to content

Commit 8c11ae0

Browse files
committed
test for await bug
causes a deadlock when cli_core_plugin await is called from node
1 parent c5d4f3c commit 8c11ae0

File tree

6 files changed

+343
-0
lines changed

6 files changed

+343
-0
lines changed

source/tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,3 +233,4 @@ add_subdirectory(metacall_plugin_extension_local_test)
233233
add_subdirectory(metacall_plugin_extension_destroy_order_test)
234234
add_subdirectory(metacall_cli_core_plugin_test)
235235
add_subdirectory(metacall_backtrace_plugin_test)
236+
add_subdirectory(await_test)
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
# Check if this loader is enabled
2+
if(NOT OPTION_BUILD_LOADERS OR NOT OPTION_BUILD_LOADERS_EXT OR NOT OPTION_BUILD_LOADERS_PY OR NOT OPTION_BUILD_LOADERS_NODE)
3+
return()
4+
endif()
5+
6+
#
7+
# Executable name and options
8+
#
9+
10+
# Target name
11+
set(target await_test)
12+
message(STATUS "Test ${target}")
13+
14+
#
15+
# Compiler warnings
16+
#
17+
18+
include(Warnings)
19+
20+
#
21+
# Compiler security
22+
#
23+
24+
include(SecurityFlags)
25+
26+
#
27+
# Sources
28+
#
29+
30+
set(include_path "${CMAKE_CURRENT_SOURCE_DIR}/include/${target}")
31+
set(source_path "${CMAKE_CURRENT_SOURCE_DIR}/source")
32+
33+
set(sources
34+
${source_path}/main.cpp
35+
${source_path}/await_test.cpp
36+
)
37+
38+
# Group source files
39+
set(header_group "Header Files (API)")
40+
set(source_group "Source Files")
41+
source_group_by_path(${include_path} "\\\\.h$|\\\\.hpp$"
42+
${header_group} ${headers})
43+
source_group_by_path(${source_path} "\\\\.cpp$|\\\\.c$|\\\\.h$|\\\\.hpp$"
44+
${source_group} ${sources})
45+
46+
#
47+
# Create executable
48+
#
49+
50+
# Build executable
51+
add_executable(${target}
52+
${sources}
53+
)
54+
55+
# Create namespaced alias
56+
add_executable(${META_PROJECT_NAME}::${target} ALIAS ${target})
57+
58+
#
59+
# Project options
60+
#
61+
62+
set_target_properties(${target}
63+
PROPERTIES
64+
${DEFAULT_PROJECT_OPTIONS}
65+
FOLDER "${IDE_FOLDER}"
66+
)
67+
68+
#
69+
# Include directories
70+
#
71+
72+
target_include_directories(${target}
73+
PRIVATE
74+
${DEFAULT_INCLUDE_DIRECTORIES}
75+
${PROJECT_BINARY_DIR}/source/include
76+
)
77+
78+
#
79+
# Libraries
80+
#
81+
82+
target_link_libraries(${target}
83+
PRIVATE
84+
${DEFAULT_LIBRARIES}
85+
86+
GTest
87+
88+
${META_PROJECT_NAME}::metacall
89+
)
90+
91+
#
92+
# Compile definitions
93+
#
94+
95+
target_compile_definitions(${target}
96+
PRIVATE
97+
${DEFAULT_COMPILE_DEFINITIONS}
98+
99+
METACALL_PLUGIN_PATH="${CMAKE_CURRENT_SOURCE_DIR}/plugins"
100+
)
101+
102+
#
103+
# Compile options
104+
#
105+
106+
target_compile_options(${target}
107+
PRIVATE
108+
${DEFAULT_COMPILE_OPTIONS}
109+
)
110+
#
111+
# Compile features
112+
#
113+
114+
target_compile_features(${target}
115+
PRIVATE
116+
cxx_std_17 # Required for filesystem
117+
)
118+
119+
#
120+
# Linker options
121+
#
122+
123+
target_link_libraries(${target}
124+
PRIVATE
125+
${DEFAULT_LINKER_OPTIONS}
126+
)
127+
128+
#
129+
# Define test
130+
#
131+
132+
add_test(NAME ${target}
133+
COMMAND $<TARGET_FILE:${target}>
134+
)
135+
136+
#
137+
# Define dependencies
138+
#
139+
140+
add_dependencies(${target}
141+
ext_loader
142+
node_loader
143+
py_loader
144+
plugin_extension
145+
)
146+
147+
#
148+
# Define test properties
149+
#
150+
151+
set_property(TEST ${target}
152+
PROPERTY LABELS ${target}
153+
)
154+
155+
include(TestEnvironmentVariables)
156+
157+
test_environment_variables(${target}
158+
""
159+
${TESTS_ENVIRONMENT_VARIABLES}
160+
)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
const { metacall, metacall_load_from_file, metacall_inspect } = require('metacall')
2+
3+
function await__test(await_cb) {
4+
metacall_load_from_file("node", ["scripts/nod.js"]);
5+
hello_await = 'hello_boy_await(1,2)';
6+
await_cb(hello_await);
7+
8+
return 22;
9+
}
10+
11+
module.exports = await__test
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"language_id": "node",
3+
"path": ".",
4+
"scripts": [
5+
"await_test.js"
6+
]
7+
}
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/*
2+
* MetaCall Library by Parra Studios
3+
* A library for providing a foreign function interface calls.
4+
*
5+
* Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia <[email protected]>
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*
19+
*/
20+
21+
#include <gtest/gtest.h>
22+
23+
#include <metacall/metacall.h>
24+
#include <metacall/metacall_loaders.h>
25+
26+
#include <filesystem>
27+
28+
namespace fs = std::filesystem;
29+
30+
class await_test : public testing::Test
31+
{
32+
public:
33+
};
34+
35+
TEST_F(await_test, DefaultConstructor)
36+
{
37+
metacall_print_info();
38+
39+
ASSERT_EQ((int)0, (int)metacall_initialize());
40+
41+
/* Extension */
42+
void *handle = metacall_plugin_extension();
43+
44+
ASSERT_NE((void *)NULL, (void *)handle);
45+
46+
void *args[] = {
47+
metacall_value_create_string(METACALL_PLUGIN_PATH, sizeof(METACALL_PLUGIN_PATH) - 1),
48+
metacall_value_create_ptr(&handle)
49+
};
50+
51+
void *result = metacallhv_s(handle, "plugin_load_from_path", args, sizeof(args) / sizeof(args[0]));
52+
53+
ASSERT_NE((void *)NULL, (void *)result);
54+
55+
EXPECT_EQ((enum metacall_value_id)METACALL_INT, (enum metacall_value_id)metacall_value_id(result));
56+
57+
EXPECT_EQ((int)0, (int)metacall_value_to_int(result));
58+
59+
metacall_value_destroy(args[0]);
60+
metacall_value_destroy(args[1]);
61+
metacall_value_destroy(result);
62+
63+
/* NodeJS */
64+
#if defined(OPTION_BUILD_LOADERS_NODE)
65+
{
66+
/* Get core plugin path and handle in order to load cli plugins */
67+
const char *plugin_path = metacall_plugin_path();
68+
void *plugin_extension_handle = metacall_plugin_extension();
69+
void *cli_plugin_handle = NULL;
70+
71+
if (plugin_path != NULL && plugin_extension_handle != NULL)
72+
{
73+
/* Define the cli plugin path as string (core plugin path plus cli) */
74+
fs::path plugin_cli_path(plugin_path);
75+
plugin_cli_path /= "cli";
76+
std::string plugin_cli_path_str(plugin_cli_path.string());
77+
78+
/* Load cli plugins into plugin cli handle */
79+
void *args[] = {
80+
metacall_value_create_string(plugin_cli_path_str.c_str(), plugin_cli_path_str.length()),
81+
metacall_value_create_ptr(&cli_plugin_handle)
82+
};
83+
84+
void *ret = metacallhv_s(plugin_extension_handle, "plugin_load_from_path", args, sizeof(args) / sizeof(args[0]));
85+
86+
if (ret == NULL || (ret != NULL && metacall_value_to_int(ret) != 0))
87+
{
88+
std::cerr << "Failed to load CLI plugins from folder: " << plugin_cli_path_str << std::endl;
89+
}
90+
91+
metacall_value_destroy(args[0]);
92+
metacall_value_destroy(args[1]);
93+
metacall_value_destroy(ret);
94+
}
95+
96+
void *func = metacall_handle_function(cli_plugin_handle, "await");
97+
if (func == NULL)
98+
std::cerr << "function not in handle\n " << METACALL_PLUGIN_PATH << '\n';
99+
void *args[] = {
100+
metacall_value_create_function(func)
101+
};
102+
void *ret = metacallhv_s(handle, "await__test", args, 1);
103+
104+
EXPECT_NE((void *)NULL, (void *)ret);
105+
106+
EXPECT_EQ((enum metacall_value_id)METACALL_DOUBLE, (enum metacall_value_id)metacall_value_id(ret));
107+
108+
EXPECT_EQ((double)22, (long)metacall_value_to_double(ret));
109+
110+
metacall_value_destroy(ret);
111+
}
112+
#endif /* OPTION_BUILD_LOADERS_NODE */
113+
114+
/* Print inspect information */
115+
{
116+
size_t size = 0;
117+
118+
struct metacall_allocator_std_type std_ctx = { &std::malloc, &std::realloc, &std::free };
119+
120+
void *allocator = metacall_allocator_create(METACALL_ALLOCATOR_STD, (void *)&std_ctx);
121+
122+
char *inspect_str = metacall_inspect(&size, allocator);
123+
124+
EXPECT_NE((char *)NULL, (char *)inspect_str);
125+
126+
EXPECT_GT((size_t)size, (size_t)0);
127+
128+
//std::cout << inspect_str << std::endl;
129+
130+
metacall_allocator_free(allocator, inspect_str);
131+
132+
metacall_allocator_destroy(allocator);
133+
}
134+
135+
EXPECT_EQ((int)0, (int)metacall_destroy());
136+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* MetaCall Library by Parra Studios
3+
* A library for providing a foreign function interface calls.
4+
*
5+
* Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia <[email protected]>
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*
19+
*/
20+
21+
#include <gtest/gtest.h>
22+
23+
int main(int argc, char *argv[])
24+
{
25+
::testing::InitGoogleTest(&argc, argv);
26+
27+
return RUN_ALL_TESTS();
28+
}

0 commit comments

Comments
 (0)