Commit e2f2721e authored by Kirill Smelkov's avatar Kirill Smelkov

go/internal/xtesting: Prepare to run user's tests with both py2 and py3

Tests, that want to verify something wrt both py2 and py3 will do
WithEachPy(tested_func) which will run tested_func two times:

1) under environment where python on $PATH points to python2, and
2) under environment where python on $PATH points to python3.

Client tests will now need to use just "python" instead of e.g.
"python2" or "python3" to run some python program, and each time
"python" will correspond to current phase of WithEachPy execution.

This will be soon handy to test things wrt e.g. ZEO/py2 and ZEO/py3
servers and similar situations.

Tests that merely want to use some python program just for their inner
working, for example to run `zodb commit`, no longer indicate their
preference for py2. For such tests it is a matter of preference in
pre-setup environment to where "python" points.

For the reference under environments created with py2py3-venv(*) default
"python" currently points to "python2".

(*) see nexedi/zodbtools@fac2f190
parent 84fed748
// Copyright (C) 2017-2021 Nexedi SA and Contributors.
// Copyright (C) 2017-2024 Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com>
//
// This program is free software: you can Use, Study, Modify and Redistribute
......@@ -39,9 +39,35 @@ import (
"lab.nexedi.com/kirr/neo/go/zodb"
)
// WithEachPy runs f for all Python versions we care about.
//
// For each version f is run separately under corresponding environment where
// `python` on $PATH runs that python version.
//
// We currently support the following versions:
//
// - python2
// - python3
func WithEachPy(t *testing.T, f func(t *testing.T)) {
tmpd := t.TempDir()
for major := 2; major <= 3; major++ {
t.Run(fmt.Sprintf("py%d", major), func(t *testing.T) {
err := os.WriteFile(tmpd + "/python", []byte("#!/bin/sh\n" +
fmt.Sprintf("exec python%d \"$@\"\n", major)), 0777)
if err != nil {
t.Fatal(err)
}
t.Setenv("PATH", fmt.Sprintf("%s%c%s", tmpd, os.PathListSeparator, os.Getenv("PATH")))
f(t)
})
}
}
var (
pyMu sync.Mutex
pyHave = map[string]bool{} // {} pymod -> y/n ; ".python" indicates python presence
pyHaveByVer = map[string]map[string]bool{} // {} pyver -> {} pymod -> y/n
)
// NeedPy skips current test if python and specified modules are not available.
......@@ -59,24 +85,30 @@ func NeedPy(t testing.TB, modules ...string) {
pyMu.Lock()
defer pyMu.Unlock()
// verify if python is present
havePy, know := pyHave[".python"]
if !know {
cmd := exec.Command("python2", "-c", "0")
err := cmd.Run()
havePy = (err == nil)
pyHave[".python"] = havePy
// verify if python is present, retrieve its version
//
// Under different WithEachPy executions python might point to
// different python versions, so we cannot cache whether we have python
// or not. Retrieving `python --version` should be relatively fast - ~5ms -
// contrary to 100-200-300ms when running python code.
cmd := exec.Command("python", "--version")
out, err := cmd.CombinedOutput() // py2 emits version to stderr, py3 to stdout
if (err != nil) {
t.Skipf("skipping: python is not available: %s\n%s", err, out)
}
pyver := string(out) // e.g. "Python 2.7.18"
if !havePy {
t.Skipf("skipping: python is not availble")
pyHave, ok := pyHaveByVer[pyver]
if !ok {
pyHave = map[string]bool{}
pyHaveByVer[pyver] = pyHave
}
var donthave []string
for _, pymod := range modules {
have, know := pyHave[pymod]
if !know {
cmd := exec.Command("python2", "-c", "import "+pymod)
cmd := exec.Command("python", "-c", "import "+pymod)
err := cmd.Run()
have = (err == nil)
pyHave[pymod] = have
......@@ -125,7 +157,7 @@ func ZPyCommitRaw(zurl string, at zodb.Tid, objv ...ZRawObject) (_ zodb.Tid, err
zin.WriteString("\n")
// run py `zodb commit`
cmd:= exec.Command("python2", "-m", "zodbtools.zodb", "commit", zurl, at.String())
cmd:= exec.Command("python", "-m", "zodbtools.zodb", "commit", zurl, at.String())
cmd.Stdin = zin
cmd.Stderr = os.Stderr
out, err := cmd.Output()
......@@ -149,7 +181,7 @@ func ZPyRestore(zurl string, zin string) (tidv []zodb.Tid, err error) {
defer xerr.Contextf(&err, "%s: zpyrestore", zurl)
// run py `zodb restore`
cmd:= exec.Command("python2", "-m", "zodbtools.zodb", "restore", zurl)
cmd:= exec.Command("python", "-m", "zodbtools.zodb", "restore", zurl)
cmd.Stdin = strings.NewReader(zin)
cmd.Stderr = os.Stderr
out, err := cmd.Output()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment