|
108 | 108 | owngil_atom_create_different_test/1, |
109 | 109 | owngil_atom_cache_test/1, |
110 | 110 | owngil_ref_roundtrip_test/1, |
111 | | - owngil_pid_operations_test/1 |
| 111 | + owngil_pid_operations_test/1, |
| 112 | + %% Channel class tests |
| 113 | + owngil_channel_class_test/1, |
| 114 | + owngil_channel_iteration_test/1, |
| 115 | + owngil_channel_context_manager_test/1, |
| 116 | + %% ByteChannel tests |
| 117 | + owngil_bytechannel_send_receive_test/1, |
| 118 | + owngil_bytechannel_try_receive_test/1, |
| 119 | + owngil_bytechannel_iteration_test/1, |
| 120 | + %% Buffer tests |
| 121 | + owngil_buffer_read_methods_test/1, |
| 122 | + owngil_buffer_at_eof_test/1 |
112 | 123 | ]). |
113 | 124 |
|
114 | 125 | all() -> |
@@ -194,7 +205,18 @@ groups() -> |
194 | 205 | owngil_atom_create_different_test, |
195 | 206 | owngil_atom_cache_test, |
196 | 207 | owngil_ref_roundtrip_test, |
197 | | - owngil_pid_operations_test |
| 208 | + owngil_pid_operations_test, |
| 209 | + %% Channel tests |
| 210 | + owngil_channel_class_test, |
| 211 | + owngil_channel_iteration_test, |
| 212 | + owngil_channel_context_manager_test, |
| 213 | + %% ByteChannel tests |
| 214 | + owngil_bytechannel_send_receive_test, |
| 215 | + owngil_bytechannel_try_receive_test, |
| 216 | + owngil_bytechannel_iteration_test, |
| 217 | + %% Buffer tests |
| 218 | + owngil_buffer_read_methods_test, |
| 219 | + owngil_buffer_at_eof_test |
198 | 220 | ]}]. |
199 | 221 |
|
200 | 222 | init_per_suite(Config) -> |
@@ -1753,3 +1775,186 @@ owngil_pid_operations_test(Config) -> |
1753 | 1775 | {ok, true} = py_context:call(Ctx, py_test_pid_send, pid_hash_equal, [Pid, Pid], #{}), |
1754 | 1776 |
|
1755 | 1777 | py_context:stop(Ctx). |
| 1778 | + |
| 1779 | +%%% ============================================================================ |
| 1780 | +%%% Channel Class Tests (erlang_api group) |
| 1781 | +%%% ============================================================================ |
| 1782 | + |
| 1783 | +%% @doc Test Channel class receive/try_receive in OWN_GIL |
| 1784 | +owngil_channel_class_test(Config) -> |
| 1785 | + {ok, Ctx} = py_context:start_link(1, owngil), |
| 1786 | + TestDir = proplists:get_value(test_dir, Config), |
| 1787 | + |
| 1788 | + ok = py_context:exec(Ctx, iolist_to_binary(io_lib:format( |
| 1789 | + "import sys; sys.path.insert(0, '~s')", [TestDir]))), |
| 1790 | + |
| 1791 | + {ok, Ch} = py_channel:new(), |
| 1792 | + |
| 1793 | + %% Send message from Erlang |
| 1794 | + ok = py_channel:send(Ch, <<"test_channel_class">>), |
| 1795 | + |
| 1796 | + %% Receive via Channel class in Python |
| 1797 | + {ok, <<"test_channel_class">>} = py_context:call(Ctx, py_test_pid_send, |
| 1798 | + channel_receive_test, [Ch], #{}), |
| 1799 | + |
| 1800 | + py_channel:close(Ch), |
| 1801 | + py_context:stop(Ctx). |
| 1802 | + |
| 1803 | +%% @doc Test Channel iteration in OWN_GIL |
| 1804 | +owngil_channel_iteration_test(Config) -> |
| 1805 | + {ok, Ctx} = py_context:start_link(1, owngil), |
| 1806 | + TestDir = proplists:get_value(test_dir, Config), |
| 1807 | + |
| 1808 | + ok = py_context:exec(Ctx, iolist_to_binary(io_lib:format( |
| 1809 | + "import sys; sys.path.insert(0, '~s')", [TestDir]))), |
| 1810 | + |
| 1811 | + {ok, Ch} = py_channel:new(), |
| 1812 | + |
| 1813 | + %% Send multiple messages |
| 1814 | + ok = py_channel:send(Ch, <<"msg1">>), |
| 1815 | + ok = py_channel:send(Ch, <<"msg2">>), |
| 1816 | + ok = py_channel:send(Ch, <<"msg3">>), |
| 1817 | + |
| 1818 | + %% Iterate in Python |
| 1819 | + {ok, 3} = py_context:call(Ctx, py_test_pid_send, |
| 1820 | + channel_iteration_test, [Ch, 3], #{}), |
| 1821 | + |
| 1822 | + py_channel:close(Ch), |
| 1823 | + py_context:stop(Ctx). |
| 1824 | + |
| 1825 | +%% @doc Test Channel as context manager in OWN_GIL |
| 1826 | +owngil_channel_context_manager_test(Config) -> |
| 1827 | + {ok, Ctx} = py_context:start_link(1, owngil), |
| 1828 | + TestDir = proplists:get_value(test_dir, Config), |
| 1829 | + |
| 1830 | + ok = py_context:exec(Ctx, iolist_to_binary(io_lib:format( |
| 1831 | + "import sys; sys.path.insert(0, '~s')", [TestDir]))), |
| 1832 | + |
| 1833 | + {ok, Ch} = py_channel:new(), |
| 1834 | + |
| 1835 | + %% Send a message for the context manager test to try_receive |
| 1836 | + ok = py_channel:send(Ch, <<"context_msg">>), |
| 1837 | + |
| 1838 | + %% Test context manager usage |
| 1839 | + {ok, true} = py_context:call(Ctx, py_test_pid_send, |
| 1840 | + channel_context_manager_test, [Ch], #{}), |
| 1841 | + |
| 1842 | + py_channel:close(Ch), |
| 1843 | + py_context:stop(Ctx). |
| 1844 | + |
| 1845 | +%%% ============================================================================ |
| 1846 | +%%% ByteChannel Tests (erlang_api group) |
| 1847 | +%%% ============================================================================ |
| 1848 | + |
| 1849 | +%% @doc Test ByteChannel send_bytes/receive_bytes in OWN_GIL |
| 1850 | +owngil_bytechannel_send_receive_test(Config) -> |
| 1851 | + {ok, Ctx} = py_context:start_link(1, owngil), |
| 1852 | + TestDir = proplists:get_value(test_dir, Config), |
| 1853 | + |
| 1854 | + ok = py_context:exec(Ctx, iolist_to_binary(io_lib:format( |
| 1855 | + "import sys; sys.path.insert(0, '~s')", [TestDir]))), |
| 1856 | + |
| 1857 | + {ok, Ch} = py_byte_channel:new(), |
| 1858 | + |
| 1859 | + %% Send bytes from Python via ByteChannel |
| 1860 | + {ok, true} = py_context:call(Ctx, py_test_pid_send, |
| 1861 | + bytechannel_send_receive_test, [Ch], #{}), |
| 1862 | + |
| 1863 | + %% Receive raw bytes from Erlang using byte channel API |
| 1864 | + {ok, <<"hello_owngil">>} = py_byte_channel:try_receive(Ch), |
| 1865 | + |
| 1866 | + py_byte_channel:close(Ch), |
| 1867 | + py_context:stop(Ctx). |
| 1868 | + |
| 1869 | +%% @doc Test ByteChannel non-blocking try_receive_bytes in OWN_GIL |
| 1870 | +owngil_bytechannel_try_receive_test(Config) -> |
| 1871 | + {ok, Ctx} = py_context:start_link(1, owngil), |
| 1872 | + TestDir = proplists:get_value(test_dir, Config), |
| 1873 | + |
| 1874 | + ok = py_context:exec(Ctx, iolist_to_binary(io_lib:format( |
| 1875 | + "import sys; sys.path.insert(0, '~s')", [TestDir]))), |
| 1876 | + |
| 1877 | + {ok, Ch} = py_byte_channel:new(), |
| 1878 | + |
| 1879 | + %% Send raw bytes from Erlang using byte channel API |
| 1880 | + ok = py_byte_channel:send(Ch, <<"bytes_data">>), |
| 1881 | + |
| 1882 | + %% Receive via ByteChannel in Python |
| 1883 | + {ok, <<"bytes_data">>} = py_context:call(Ctx, py_test_pid_send, |
| 1884 | + bytechannel_try_receive_test, [Ch], #{}), |
| 1885 | + |
| 1886 | + py_byte_channel:close(Ch), |
| 1887 | + py_context:stop(Ctx). |
| 1888 | + |
| 1889 | +%% @doc Test ByteChannel iteration in OWN_GIL |
| 1890 | +owngil_bytechannel_iteration_test(Config) -> |
| 1891 | + {ok, Ctx} = py_context:start_link(1, owngil), |
| 1892 | + TestDir = proplists:get_value(test_dir, Config), |
| 1893 | + |
| 1894 | + ok = py_context:exec(Ctx, iolist_to_binary(io_lib:format( |
| 1895 | + "import sys; sys.path.insert(0, '~s')", [TestDir]))), |
| 1896 | + |
| 1897 | + {ok, Ch} = py_byte_channel:new(), |
| 1898 | + |
| 1899 | + %% Send multiple byte chunks using byte channel API |
| 1900 | + ok = py_byte_channel:send(Ch, <<"chunk1">>), |
| 1901 | + ok = py_byte_channel:send(Ch, <<"chunk2">>), |
| 1902 | + |
| 1903 | + %% Iterate in Python |
| 1904 | + {ok, 2} = py_context:call(Ctx, py_test_pid_send, |
| 1905 | + bytechannel_iteration_test, [Ch, 2], #{}), |
| 1906 | + |
| 1907 | + py_byte_channel:close(Ch), |
| 1908 | + py_context:stop(Ctx). |
| 1909 | + |
| 1910 | +%%% ============================================================================ |
| 1911 | +%%% Buffer Tests (erlang_api group) |
| 1912 | +%%% ============================================================================ |
| 1913 | + |
| 1914 | +%% @doc Test buffer read/read_nonblock/readable_amount in OWN_GIL |
| 1915 | +owngil_buffer_read_methods_test(Config) -> |
| 1916 | + {ok, Ctx} = py_context:start_link(1, owngil), |
| 1917 | + TestDir = proplists:get_value(test_dir, Config), |
| 1918 | + |
| 1919 | + ok = py_context:exec(Ctx, iolist_to_binary(io_lib:format( |
| 1920 | + "import sys; sys.path.insert(0, '~s')", [TestDir]))), |
| 1921 | + |
| 1922 | + {ok, Buf} = py_buffer:new(), |
| 1923 | + |
| 1924 | + %% Write data to buffer |
| 1925 | + ok = py_buffer:write(Buf, <<"test_data">>), |
| 1926 | + |
| 1927 | + %% Test read methods from Python |
| 1928 | + {ok, Result} = py_context:call(Ctx, py_test_pid_send, |
| 1929 | + buffer_read_methods_test, [Buf], #{}), |
| 1930 | + |
| 1931 | + %% Verify readable amount and data |
| 1932 | + #{<<"readable">> := Readable, <<"data">> := Data} = Result, |
| 1933 | + true = Readable > 0, |
| 1934 | + <<"test_data">> = Data, |
| 1935 | + |
| 1936 | + py_buffer:close(Buf), |
| 1937 | + py_context:stop(Ctx). |
| 1938 | + |
| 1939 | +%% @doc Test buffer at_eof detection in OWN_GIL |
| 1940 | +owngil_buffer_at_eof_test(Config) -> |
| 1941 | + {ok, Ctx} = py_context:start_link(1, owngil), |
| 1942 | + TestDir = proplists:get_value(test_dir, Config), |
| 1943 | + |
| 1944 | + ok = py_context:exec(Ctx, iolist_to_binary(io_lib:format( |
| 1945 | + "import sys; sys.path.insert(0, '~s')", [TestDir]))), |
| 1946 | + |
| 1947 | + {ok, Buf} = py_buffer:new(), |
| 1948 | + |
| 1949 | + %% Buffer not yet at EOF (not closed) |
| 1950 | + {ok, false} = py_context:call(Ctx, py_test_pid_send, |
| 1951 | + buffer_at_eof_test, [Buf], #{}), |
| 1952 | + |
| 1953 | + %% Close buffer |
| 1954 | + ok = py_buffer:close(Buf), |
| 1955 | + |
| 1956 | + %% Now at EOF |
| 1957 | + {ok, true} = py_context:call(Ctx, py_test_pid_send, |
| 1958 | + buffer_at_eof_test, [Buf], #{}), |
| 1959 | + |
| 1960 | + py_context:stop(Ctx). |
0 commit comments