Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitac782bb

Browse files
[New] OsOps::execute_command supports a transfer of environment variables (exec_env) (#239)
* [New] OsOps::execute_command supports a transfer of environment variables (exec_env)New feature allows to pass environment variables to an executed program.If variable in exec_env has None value, then this variable will be unset.PostgresNode::start and PostgresNode::slow_start supports exec_env.
1 parent2401474 commitac782bb

File tree

5 files changed

+177
-22
lines changed

5 files changed

+177
-22
lines changed

‎testgres/node.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1020,7 +1020,7 @@ def get_control_data(self):
10201020

10211021
returnout_dict
10221022

1023-
defslow_start(self,replica=False,dbname='template1',username=None,max_attempts=0):
1023+
defslow_start(self,replica=False,dbname='template1',username=None,max_attempts=0,exec_env=None):
10241024
"""
10251025
Starts the PostgreSQL instance and then polls the instance
10261026
until it reaches the expected state (primary or replica). The state is checked
@@ -1033,7 +1033,9 @@ def slow_start(self, replica=False, dbname='template1', username=None, max_attem
10331033
If False, waits for the instance to be in primary mode. Default is False.
10341034
max_attempts:
10351035
"""
1036-
self.start()
1036+
assertexec_envisNoneortype(exec_env)==dict# noqa: E721
1037+
1038+
self.start(exec_env=exec_env)
10371039

10381040
ifreplica:
10391041
query='SELECT pg_is_in_recovery()'
@@ -1065,7 +1067,7 @@ def _detect_port_conflict(self, log_files0, log_files1):
10651067
returnTrue
10661068
returnFalse
10671069

1068-
defstart(self,params=[],wait=True):
1070+
defstart(self,params=[],wait=True,exec_env=None):
10691071
"""
10701072
Starts the PostgreSQL node using pg_ctl if node has not been started.
10711073
By default, it waits for the operation to complete before returning.
@@ -1079,7 +1081,7 @@ def start(self, params=[], wait=True):
10791081
Returns:
10801082
This instance of :class:`.PostgresNode`.
10811083
"""
1082-
1084+
assertexec_envisNoneortype(exec_env)==dict# noqa: E721
10831085
assert__class__._C_MAX_START_ATEMPTS>1
10841086

10851087
ifself.is_started:
@@ -1098,7 +1100,7 @@ def start(self, params=[], wait=True):
10981100

10991101
defLOCAL__start_node():
11001102
# 'error' will be None on Windows
1101-
_,_,error=execute_utility2(self.os_ops,_params,self.utils_log_file,verbose=True)
1103+
_,_,error=execute_utility2(self.os_ops,_params,self.utils_log_file,verbose=True,exec_env=exec_env)
11021104
asserterrorisNoneortype(error)==str# noqa: E721
11031105
iferrorand'does not exist'inerror:
11041106
raiseException(error)

‎testgres/operations/local_ops.py

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
importsocket
1010

1111
importpsutil
12+
importtyping
1213

1314
from ..exceptionsimportExecUtilException
1415
from ..exceptionsimportInvalidOperationException
@@ -46,9 +47,34 @@ def _process_output(encoding, temp_file_path):
4647
output=output.decode(encoding)
4748
returnoutput,None# In Windows stderr writing in stdout
4849

49-
def_run_command__nt(self,cmd,shell,input,stdin,stdout,stderr,get_process,timeout,encoding):
50+
def_run_command__nt(self,cmd,shell,input,stdin,stdout,stderr,get_process,timeout,encoding,exec_env=None):
51+
assertexec_envisNoneortype(exec_env)==dict# noqa: E721
52+
5053
# TODO: why don't we use the data from input?
5154

55+
extParams:typing.Dict[str,str]=dict()
56+
57+
ifexec_envisNone:
58+
pass
59+
eliflen(exec_env)==0:
60+
pass
61+
else:
62+
env=os.environ.copy()
63+
asserttype(env)==dict# noqa: E721
64+
forvinexec_env.items():
65+
asserttype(v)==tuple# noqa: E721
66+
assertlen(v)==2
67+
asserttype(v[0])==str# noqa: E721
68+
assertv[0]!=""
69+
70+
ifv[1]isNone:
71+
env.pop(v[0],None)
72+
else:
73+
asserttype(v[1])==str# noqa: E721
74+
env[v[0]]=v[1]
75+
76+
extParams["env"]=env
77+
5278
withtempfile.NamedTemporaryFile(mode='w+b',delete=False)astemp_file:
5379
stdout=temp_file
5480
stderr=subprocess.STDOUT
@@ -58,6 +84,7 @@ def _run_command__nt(self, cmd, shell, input, stdin, stdout, stderr, get_process
5884
stdin=stdinorsubprocess.PIPEifinputisnotNoneelseNone,
5985
stdout=stdout,
6086
stderr=stderr,
87+
**extParams,
6188
)
6289
ifget_process:
6390
returnprocess,None,None
@@ -69,19 +96,45 @@ def _run_command__nt(self, cmd, shell, input, stdin, stdout, stderr, get_process
6996
output,error=self._process_output(encoding,temp_file_path)
7097
returnprocess,output,error
7198

72-
def_run_command__generic(self,cmd,shell,input,stdin,stdout,stderr,get_process,timeout,encoding):
99+
def_run_command__generic(self,cmd,shell,input,stdin,stdout,stderr,get_process,timeout,encoding,exec_env=None):
100+
assertexec_envisNoneortype(exec_env)==dict# noqa: E721
101+
73102
input_prepared=None
74103
ifnotget_process:
75104
input_prepared=Helpers.PrepareProcessInput(input,encoding)# throw
76105

77106
assertinput_preparedisNoneor (type(input_prepared)==bytes)# noqa: E721
78107

108+
extParams:typing.Dict[str,str]=dict()
109+
110+
ifexec_envisNone:
111+
pass
112+
eliflen(exec_env)==0:
113+
pass
114+
else:
115+
env=os.environ.copy()
116+
asserttype(env)==dict# noqa: E721
117+
forvinexec_env.items():
118+
asserttype(v)==tuple# noqa: E721
119+
assertlen(v)==2
120+
asserttype(v[0])==str# noqa: E721
121+
assertv[0]!=""
122+
123+
ifv[1]isNone:
124+
env.pop(v[0],None)
125+
else:
126+
asserttype(v[1])==str# noqa: E721
127+
env[v[0]]=v[1]
128+
129+
extParams["env"]=env
130+
79131
process=subprocess.Popen(
80132
cmd,
81133
shell=shell,
82134
stdin=stdinorsubprocess.PIPEifinputisnotNoneelseNone,
83135
stdout=stdoutorsubprocess.PIPE,
84136
stderr=stderrorsubprocess.PIPE,
137+
**extParams
85138
)
86139
assertnot (processisNone)
87140
ifget_process:
@@ -100,25 +153,26 @@ def _run_command__generic(self, cmd, shell, input, stdin, stdout, stderr, get_pr
100153
error=error.decode(encoding)
101154
returnprocess,output,error
102155

103-
def_run_command(self,cmd,shell,input,stdin,stdout,stderr,get_process,timeout,encoding):
156+
def_run_command(self,cmd,shell,input,stdin,stdout,stderr,get_process,timeout,encoding,exec_env=None):
104157
"""Execute a command and return the process and its output."""
105158
ifos.name=='nt'andstdoutisNone:# Windows
106159
method=__class__._run_command__nt
107160
else:# Other OS
108161
method=__class__._run_command__generic
109162

110-
returnmethod(self,cmd,shell,input,stdin,stdout,stderr,get_process,timeout,encoding)
163+
returnmethod(self,cmd,shell,input,stdin,stdout,stderr,get_process,timeout,encoding,exec_env=exec_env)
111164

112165
defexec_command(self,cmd,wait_exit=False,verbose=False,expect_error=False,encoding=None,shell=False,
113166
text=False,input=None,stdin=None,stdout=None,stderr=None,get_process=False,timeout=None,
114-
ignore_errors=False):
167+
ignore_errors=False,exec_env=None):
115168
"""
116169
Execute a command in a subprocess and handle the output based on the provided parameters.
117170
"""
118171
asserttype(expect_error)==bool# noqa: E721
119172
asserttype(ignore_errors)==bool# noqa: E721
173+
assertexec_envisNoneortype(exec_env)==dict# noqa: E721
120174

121-
process,output,error=self._run_command(cmd,shell,input,stdin,stdout,stderr,get_process,timeout,encoding)
175+
process,output,error=self._run_command(cmd,shell,input,stdin,stdout,stderr,get_process,timeout,encoding,exec_env=exec_env)
122176
ifget_process:
123177
returnprocess
124178

‎testgres/operations/remote_ops.py

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,16 @@ def __enter__(self):
6464

6565
defexec_command(self,cmd,wait_exit=False,verbose=False,expect_error=False,
6666
encoding=None,shell=True,text=False,input=None,stdin=None,stdout=None,
67-
stderr=None,get_process=None,timeout=None,ignore_errors=False):
67+
stderr=None,get_process=None,timeout=None,ignore_errors=False,
68+
exec_env=None):
6869
"""
6970
Execute a command in the SSH session.
7071
Args:
7172
- cmd (str): The command to be executed.
7273
"""
7374
asserttype(expect_error)==bool# noqa: E721
7475
asserttype(ignore_errors)==bool# noqa: E721
76+
assertexec_envisNoneortype(exec_env)==dict# noqa: E721
7577

7678
input_prepared=None
7779
ifnotget_process:
@@ -88,7 +90,7 @@ def exec_command(self, cmd, wait_exit=False, verbose=False, expect_error=False,
8890

8991
asserttype(cmd_s)==str# noqa: E721
9092

91-
cmd_items=__class__._make_exec_env_list()
93+
cmd_items=__class__._make_exec_env_list(exec_env=exec_env)
9294
cmd_items.append(cmd_s)
9395

9496
env_cmd_s=';'.join(cmd_items)
@@ -670,14 +672,38 @@ def _is_port_free__process_1(error: str) -> bool:
670672
returnTrue
671673

672674
@staticmethod
673-
def_make_exec_env_list()->typing.List[str]:
674-
result:typing.List[str]=list()
675+
def_make_exec_env_list(exec_env:typing.Dict)->typing.List[str]:
676+
env:typing.Dict[str,str]=dict()
677+
678+
# ---------------------------------- SYSTEM ENV
675679
forenvvarinos.environ.items():
676-
ifnot__class__._does_put_envvar_into_exec_cmd(envvar[0]):
677-
continue
678-
qvalue=__class__._quote_envvar(envvar[1])
679-
asserttype(qvalue)==str# noqa: E721
680-
result.append(envvar[0]+"="+qvalue)
680+
if__class__._does_put_envvar_into_exec_cmd(envvar[0]):
681+
env[envvar[0]]=envvar[1]
682+
683+
# ---------------------------------- EXEC (LOCAL) ENV
684+
ifexec_envisNone:
685+
pass
686+
else:
687+
forenvvarinexec_env.items():
688+
asserttype(envvar)==tuple# noqa: E721
689+
assertlen(envvar)==2
690+
asserttype(envvar[0])==str# noqa: E721
691+
env[envvar[0]]=envvar[1]
692+
693+
# ---------------------------------- FINAL BUILD
694+
result:typing.List[str]=list()
695+
forenvvarinenv.items():
696+
asserttype(envvar)==tuple# noqa: E721
697+
assertlen(envvar)==2
698+
asserttype(envvar[0])==str# noqa: E721
699+
700+
ifenvvar[1]isNone:
701+
result.append("unset "+envvar[0])
702+
else:
703+
asserttype(envvar[1])==str# noqa: E721
704+
qvalue=__class__._quote_envvar(envvar[1])
705+
asserttype(qvalue)==str# noqa: E721
706+
result.append(envvar[0]+"="+qvalue)
681707
continue
682708

683709
returnresult

‎testgres/utils.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,17 +96,26 @@ def execute_utility(args, logfile=None, verbose=False):
9696
returnexecute_utility2(tconf.os_ops,args,logfile,verbose)
9797

9898

99-
defexecute_utility2(os_ops:OsOperations,args,logfile=None,verbose=False,ignore_errors=False):
99+
defexecute_utility2(
100+
os_ops:OsOperations,
101+
args,
102+
logfile=None,
103+
verbose=False,
104+
ignore_errors=False,
105+
exec_env=None,
106+
):
100107
assertos_opsisnotNone
101108
assertisinstance(os_ops,OsOperations)
102109
asserttype(verbose)==bool# noqa: E721
103110
asserttype(ignore_errors)==bool# noqa: E721
111+
assertexec_envisNoneortype(exec_env)==dict# noqa: E721
104112

105113
exit_status,out,error=os_ops.exec_command(
106114
args,
107115
verbose=True,
108116
ignore_errors=ignore_errors,
109-
encoding=OsHelpers.GetDefaultEncoding())
117+
encoding=OsHelpers.GetDefaultEncoding(),
118+
exec_env=exec_env)
110119

111120
out=''ifnotoutelseout
112121

‎tests/test_os_ops_common.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,70 @@ def test_exec_command_failure__expect_error(self, os_ops: OsOperations):
9393
assertb"nonexistent_command"inerror
9494
assertb"not found"inerror
9595

96+
deftest_exec_command_with_exec_env(self,os_ops:OsOperations):
97+
assertisinstance(os_ops,OsOperations)
98+
99+
RunConditions.skip_if_windows()
100+
101+
C_ENV_NAME="TESTGRES_TEST__EXEC_ENV_20250414"
102+
103+
cmd= ["sh","-c","echo ${}".format(C_ENV_NAME)]
104+
105+
exec_env= {C_ENV_NAME:"Hello!"}
106+
107+
response=os_ops.exec_command(cmd,exec_env=exec_env)
108+
assertresponseisnotNone
109+
asserttype(response)==bytes# noqa: E721
110+
assertresponse==b'Hello!\n'
111+
112+
response=os_ops.exec_command(cmd)
113+
assertresponseisnotNone
114+
asserttype(response)==bytes# noqa: E721
115+
assertresponse==b'\n'
116+
117+
deftest_exec_command__test_unset(self,os_ops:OsOperations):
118+
assertisinstance(os_ops,OsOperations)
119+
120+
RunConditions.skip_if_windows()
121+
122+
C_ENV_NAME="LANG"
123+
124+
cmd= ["sh","-c","echo ${}".format(C_ENV_NAME)]
125+
126+
response1=os_ops.exec_command(cmd)
127+
assertresponse1isnotNone
128+
asserttype(response1)==bytes# noqa: E721
129+
130+
ifresponse1==b'\n':
131+
logging.warning("Environment variable {} is not defined.".format(C_ENV_NAME))
132+
return
133+
134+
exec_env= {C_ENV_NAME:None}
135+
response2=os_ops.exec_command(cmd,exec_env=exec_env)
136+
assertresponse2isnotNone
137+
asserttype(response2)==bytes# noqa: E721
138+
assertresponse2==b'\n'
139+
140+
response3=os_ops.exec_command(cmd)
141+
assertresponse3isnotNone
142+
asserttype(response3)==bytes# noqa: E721
143+
assertresponse3==response1
144+
145+
deftest_exec_command__test_unset_dummy_var(self,os_ops:OsOperations):
146+
assertisinstance(os_ops,OsOperations)
147+
148+
RunConditions.skip_if_windows()
149+
150+
C_ENV_NAME="TESTGRES_TEST__DUMMY_VAR_20250414"
151+
152+
cmd= ["sh","-c","echo ${}".format(C_ENV_NAME)]
153+
154+
exec_env= {C_ENV_NAME:None}
155+
response2=os_ops.exec_command(cmd,exec_env=exec_env)
156+
assertresponse2isnotNone
157+
asserttype(response2)==bytes# noqa: E721
158+
assertresponse2==b'\n'
159+
96160
deftest_is_executable_true(self,os_ops:OsOperations):
97161
"""
98162
Test is_executable for an existing executable.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp