1 /*
2  * Copyright (C) 2020 Linux Studio Plugins Project <https://lsp-plug.in/>
3  *           (C) 2020 Vladimir Sadovnikov <sadko4u@gmail.com>
4  *
5  * This file is part of lsp-plugins
6  * Created on: 13 авг. 2019 г.
7  *
8  * lsp-plugins is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * any later version.
12  *
13  * lsp-plugins is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with lsp-plugins. If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #include <core/alloc.h>
23 #include <test/utest.h>
24 #include <core/ipc/Process.h>
25 #include <core/ipc/Thread.h>
26 #include <core/system.h>
27 
28 using namespace lsp;
29 
30 #define ENV_VAR_NAME        "LSP_TEST_ENV_VAR"
31 
32 UTEST_BEGIN("core.ipc", process)
33     UTEST_TIMELIMIT(10)
34 
test_envs(ipc::Process & p)35     void test_envs(ipc::Process &p)
36     {
37         size_t envs = p.envs();
38         UTEST_ASSERT(envs > 0);
39         LSPString key, value;
40 
41         for (size_t i=0; i<envs; ++i)
42         {
43             UTEST_ASSERT(p.read_env(i, &key, &value) == STATUS_OK);
44             printf("  env: %s = %s\n", key.get_native(), value.get_native());
45         }
46 
47         UTEST_ASSERT(p.get_env(ENV_VAR_NAME, &value) == STATUS_NOT_FOUND);
48         UTEST_ASSERT(p.set_env(ENV_VAR_NAME, "123456") == STATUS_OK);
49         UTEST_ASSERT(envs == (p.envs() - 1));
50         value.clear();
51         UTEST_ASSERT(p.get_env(ENV_VAR_NAME, &value) == STATUS_OK);
52         printf("get_env(%s) = %s\n", ENV_VAR_NAME, value.get_native());
53         UTEST_ASSERT(value.equals_ascii("123456"));
54         value.clear();
55         UTEST_ASSERT(p.remove_env(ENV_VAR_NAME, &value) == STATUS_OK);
56         UTEST_ASSERT(value.equals_ascii("123456"));
57         UTEST_ASSERT(envs == p.envs());
58         UTEST_ASSERT(p.clear_env() == STATUS_OK);
59         UTEST_ASSERT(p.envs() == 0);
60         UTEST_ASSERT(p.copy_env() == STATUS_OK);
61         UTEST_ASSERT(p.envs() == envs);
62     }
63 
test_args(ipc::Process & p)64     void test_args(ipc::Process &p)
65     {
66         UTEST_ASSERT(p.args() == 0);
67         LSPString tmp;
68         char *ctmp = NULL;
69 
70         UTEST_ASSERT(p.add_arg("arg1") == STATUS_OK);
71         UTEST_ASSERT(p.add_arg("arg4") == STATUS_OK);
72         UTEST_ASSERT(tmp.set_ascii("arg3"));
73         UTEST_ASSERT(p.add_arg(&tmp) == STATUS_OK);
74         UTEST_ASSERT(p.insert_arg(1, "arg2") == STATUS_OK);
75         UTEST_ASSERT(p.args() == 4);
76         UTEST_ASSERT(p.remove_arg(2, &tmp) == STATUS_OK);
77         UTEST_ASSERT(tmp.equals_ascii("arg4"));
78         UTEST_ASSERT(p.args() == 3);
79 
80         UTEST_ASSERT(p.get_arg(0, &ctmp) == STATUS_OK);
81         UTEST_ASSERT(strcmp(ctmp, "arg1") == 0);
82         ::free(ctmp);
83 
84         UTEST_ASSERT(p.get_arg(1, &ctmp) == STATUS_OK);
85         UTEST_ASSERT(strcmp(ctmp, "arg2") == 0);
86         ::free(ctmp);
87 
88         tmp.clear();
89         UTEST_ASSERT(p.get_arg(2, &tmp) == STATUS_OK);
90         UTEST_ASSERT(tmp.equals_ascii("arg3"));
91 
92         UTEST_ASSERT(p.clear_args() == STATUS_OK);
93         UTEST_ASSERT(p.args() == 0);
94     }
95 
96     UTEST_MAIN
97     {
98         if (argc <= 0)
99         {
100             ipc::Process p;
101             test_envs(p);
102             test_args(p);
103 
104             LSPString cmd;
105 #ifdef PLATFORM_WINDOWS
106             UTEST_ASSERT(cmd.set_utf8(executable()));
107 #else
108             UTEST_ASSERT(cmd.set_native(executable()));
109 #endif
110 
111             // Form the command line
112             p.set_command(&cmd);
113             p.add_arg("utest");
114             p.add_arg("--debug");
115             p.add_arg("--verbose");
116             p.add_arg("--nofork");
117             p.add_arg(full_name());
118             p.add_arg("--args");
119             p.add_arg("child");
120             p.add_arg("arg1");
121             p.add_arg("arg2");
122 
123             // Set environment
124             p.set_env(ENV_VAR_NAME, "test_value");
125 
126             // Redirect stdout and stderr
127             io::IInStream *xstdout = p.get_stdout();
128             UTEST_ASSERT(xstdout != NULL);
129             io::IInStream *xstderr = p.get_stderr();
130             UTEST_ASSERT(xstderr != NULL);
131 
132             // Launch the process
133             printf("Starting child process...\n");
134             UTEST_ASSERT(p.process_id() < 0);
135             UTEST_ASSERT(p.launch() == STATUS_OK);
136             printf("Started child process, pid=%d\n", int(p.process_id()));
137             UTEST_ASSERT(p.wait(0) == STATUS_OK); // Test process status
138             UTEST_ASSERT(p.wait(200) == STATUS_OK); // Wait for a short while
139             UTEST_ASSERT(p.status() == ipc::Process::PSTATUS_RUNNING); // Check status
140             printf("Waiting for process...\n");
141             UTEST_ASSERT(p.wait() == STATUS_OK); // Wait until termination
142 
143             // Close stdout and stderr
144             UTEST_ASSERT(xstdout->close() == STATUS_OK);
145             UTEST_ASSERT(xstderr->close() == STATUS_OK);
146 
147             // Analyze exit status
148             int code = 0;
149             UTEST_ASSERT(p.exit_code(&code) == STATUS_OK);
150             printf("Waited process has terminated with code=%d\n", int(code));
151             UTEST_ASSERT(code == 0);
152 
153             printf("Parent process has exited\n");
154         }
155         else
156         {
157             printf("Child process started\n");
158 
159             // Perform argument check
160             UTEST_ASSERT(argc == 3);
161             UTEST_ASSERT(strcmp(argv[0], "child") == 0);
162             UTEST_ASSERT(strcmp(argv[1], "arg1") == 0);
163             UTEST_ASSERT(strcmp(argv[2], "arg2") == 0);
164 
165             LSPString value;
166             UTEST_ASSERT(system::get_env_var(ENV_VAR_NAME, &value) == STATUS_OK);
167             UTEST_ASSERT(value.equals_ascii("test_value"));
168 
169             // Perform a sleep for synchronization with caller
170             printf("Entering sleep\n");
171             ipc::Thread::sleep(2 * 1000);
172             printf("Child process has exited\n");
173         }
174     }
175 UTEST_END;
176 
177 
178