Commit ed2b96ca authored by Kirill Smelkov's avatar Kirill Smelkov

go/zodb: Test PyData and Map/List on all py2/py3 kinds of data we care about

Previously we were testing PyData and Map/List only with data generated by python2
and pickle protocol=2. However even on py2 there are more pickle
protocols that are in use, and also there is python3.

-> Modernize py/pydata-gen-testdata to use run_with_all_zodb_pickle_kinds
   that was recently added as part of nexedi/zodbtools@f9d36ba7
   and generate test data with both python2 and python3. It is handy to
   use py2py3-venv(*) to prepare python environment to do that.

   Adjust tests on Go side to verify how PyData and Map/List handle all generated
   zkinds.

py2_pickle1, py2_pickle2 and py2_pickle3 are handled well.
Tests for py3_pickle3 currently fail and so are marked with "xfail".

We will fix tests for py3_pickle3 in the next patches.

(*) see nexedi/zodbtools@fac2f190
parent 15401594
...@@ -25,16 +25,29 @@ import ( ...@@ -25,16 +25,29 @@ import (
"lab.nexedi.com/kirr/neo/go/zodb" "lab.nexedi.com/kirr/neo/go/zodb"
pickle "github.com/kisielk/og-rek" pickle "github.com/kisielk/og-rek"
"lab.nexedi.com/kirr/neo/go/internal/xtesting"
assert "github.com/stretchr/testify/require" assert "github.com/stretchr/testify/require"
) )
// ztestdataReg maintains registry of all entries under testdata/ .
var ztestdataReg = xtesting.ZTestDataRegistry[struct{}]{}
type ZTestData = xtesting.ZTestData[struct{}]
// Verify that Map and List can load from data saved by py. // Verify that Map and List can load from data saved by py.
// TODO go saves Map/List -> py loads and checks. // TODO go saves Map/List -> py loads and checks.
func TestPersistentMapListLoad(t0 *testing.T) { func TestPersistentMapListLoad(t *testing.T) {
ztestdataReg.RunWithEach(t, _TestPersistentMapListLoad)
}
func _TestPersistentMapListLoad(t0 *testing.T, z *ZTestData) {
if z.Kind == "py3_pickle3" {
t0.Skip("xfail")
}
assert := assert.New(t0) assert := assert.New(t0)
tdb := zodb.OpenTestDB(t0, "testdata/data.fs") tdb := zodb.OpenTestDB(t0, z.Path("data.fs"))
defer tdb.Close() defer tdb.Close()
t := tdb.Open(&zodb.ConnOptions{}) t := tdb.Open(&zodb.ConnOptions{})
......
#!/usr/bin/env python2 #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright (C) 2017-2024 Nexedi SA and Contributors. # Copyright (C) 2017-2024 Nexedi SA and Contributors.
# Kirill Smelkov <kirr@nexedi.com> # Kirill Smelkov <kirr@nexedi.com>
...@@ -20,23 +20,35 @@ ...@@ -20,23 +20,35 @@
# See https://www.nexedi.com/licensing for rationale and options. # See https://www.nexedi.com/licensing for rationale and options.
"""generate reference database and pickle objects encoding for tests""" """generate reference database and pickle objects encoding for tests"""
from __future__ import print_function
from ZODB import DB, serialize from ZODB import DB, serialize
from ZODB.utils import z64 from ZODB.utils import z64
from persistent.mapping import PersistentMapping from persistent.mapping import PersistentMapping
from persistent.list import PersistentList from persistent.list import PersistentList
import transaction import transaction
from zodbtools.test.gen_testdata import run_with_zodb4py2_compat from zodbtools.test.gen_testdata import run_with_all_zodb_pickle_kinds, current_zkind
from golang.gcompat import qq from golang.gcompat import qq
from os import remove from os import makedirs
from os.path import exists from os.path import exists, relpath
from shutil import rmtree
from six import PY3
if PY3:
from importlib import reload
else:
reload # available as builtin
# gen_ztestdata generates test databases that ZODB/go will try to load. # gen_ztestdata generates test databases that ZODB/go will try to load.
def gen_ztestdata(): def gen_ztestdata():
outfs = "testdata/data.fs" zkind = current_zkind()
if exists(outfs): prefix = "testdata/%s" % zkind
remove(outfs) if exists(prefix):
remove(outfs+".index") rmtree(prefix)
makedirs(prefix)
outfs = "%s/data.fs" % prefix
db = DB(outfs) db = DB(outfs)
conn = db.open() conn = db.open()
root = conn.root() root = conn.root()
...@@ -50,17 +62,29 @@ def gen_ztestdata(): ...@@ -50,17 +62,29 @@ def gen_ztestdata():
transaction.commit() transaction.commit()
with open("ztestdata_%s_x_test.go" % zkind, "w") as f:
def emit(v):
print(v, file=f)
emit("// Code generated by %s; DO NOT EDIT." % relpath(__file__))
emit("package zodb_test")
emit("func init() {")
emit("\tztestdataReg.Register(%s, %s, nil)" % (qq(zkind), qq(prefix)))
emit("}")
# gen_test_pydata generates testdata for PyData serialization tests. # gen_test_pydata generates testdata for PyData serialization tests.
def gen_test_pydata(): def gen_test_pydata():
# import ZODB.tests at runtime after ZODB.X._protocol is patched # import ZODB.tests at runtime after ZODB.X._protocol is patched
# reload the module each time because SerializerTestCase uses make_pickle to initialize class-level attributes
from ZODB.tests import testSerialize from ZODB.tests import testSerialize
reload(testSerialize)
# dump to go what to expect # dump to go what to expect
with open("ztestdata_pydata_test.go", "w") as f: zkind = current_zkind()
with open("ztestdata_pydata_%s_test.go" % zkind, "w") as f:
def emit(v): def emit(v):
print >>f, v print(v, file=f)
emit("// Code generated by %s; DO NOT EDIT." % __file__) emit("// Code generated by %s; DO NOT EDIT." % relpath(__file__))
emit("package zodb") emit("package zodb")
# [] of pickle # [] of pickle
...@@ -74,18 +98,20 @@ def gen_test_pydata(): ...@@ -74,18 +98,20 @@ def gen_test_pydata():
r = serialize.ObjectReader(factory=testSerialize._factory) r = serialize.ObjectReader(factory=testSerialize._factory)
emit("\nvar _PyData_ClassName_Testv = [...]_PyDataClassName_TestEntry{") emit("func init() {")
emit("\t_PyDataClassName_TestDataRegistry[%s] = []_PyDataClassName_TestEntry{" % qq(zkind))
for test in testv: for test in testv:
emit("\t{") emit("\t\t{")
emit("\t\t%s," % qq(test)) emit("\t\t\t%s," % qq(test))
emit("\t\t%s," % qq(r.getClassName(test))) emit("\t\t\t%s," % qq(r.getClassName(test)))
emit("\t},") emit("\t\t},")
emit('\t{"aaa", "?.?"},') # invalid emit('\t\t{"aaa", "?.?"},') # invalid
emit("\t}")
emit("}") emit("}")
def main(): def main():
run_with_zodb4py2_compat(gen_ztestdata) run_with_all_zodb_pickle_kinds(gen_ztestdata)
run_with_zodb4py2_compat(gen_test_pydata) run_with_all_zodb_pickle_kinds(gen_test_pydata)
if __name__ == '__main__': if __name__ == '__main__':
main() main()
// Copyright (C) 2016-2017 Nexedi SA and Contributors. // Copyright (C) 2016-2024 Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com> // Kirill Smelkov <kirr@nexedi.com>
// //
// This program is free software: you can Use, Study, Modify and Redistribute // This program is free software: you can Use, Study, Modify and Redistribute
...@@ -19,10 +19,13 @@ ...@@ -19,10 +19,13 @@
package zodb package zodb
//go:generate ./py/pydata-gen-testdata //go:generate python2 py/pydata-gen-testdata
//go:generate python3 py/pydata-gen-testdata
import ( import (
"testing" "testing"
"lab.nexedi.com/kirr/neo/go/internal/xmaps"
) )
type _PyDataClassName_TestEntry struct { type _PyDataClassName_TestEntry struct {
...@@ -30,7 +33,20 @@ type _PyDataClassName_TestEntry struct { ...@@ -30,7 +33,20 @@ type _PyDataClassName_TestEntry struct {
className string className string
} }
var _PyDataClassName_TestDataRegistry = map[/*zkind*/string][]_PyDataClassName_TestEntry{}
func TestPyClassName(t *testing.T) { func TestPyClassName(t *testing.T) {
for _, zkind := range xmaps.SortedKeys(_PyDataClassName_TestDataRegistry) {
t.Run(zkind, func(t *testing.T) {
if zkind == "py3_pickle3" {
t.Skip("xfail")
}
_TestPyClassName(t, _PyDataClassName_TestDataRegistry[zkind])
})
}
}
func _TestPyClassName(t *testing.T, _PyData_ClassName_Testv []_PyDataClassName_TestEntry) {
for _, tt := range _PyData_ClassName_Testv { for _, tt := range _PyData_ClassName_Testv {
className := PyData(tt.pydata).ClassName() className := PyData(tt.pydata).ClassName()
if className != tt.className { if className != tt.className {
......
K.N.
\ No newline at end of file
K.N.
\ No newline at end of file
K.N.
\ No newline at end of file
// Code generated by py/pydata-gen-testdata; DO NOT EDIT.
package zodb_test
func init() {
ztestdataReg.Register("py2_pickle1", "testdata/py2_pickle1", nil)
}
// Code generated by py/pydata-gen-testdata; DO NOT EDIT.
package zodb_test
func init() {
ztestdataReg.Register("py2_pickle2", "testdata/py2_pickle2", nil)
}
// Code generated by py/pydata-gen-testdata; DO NOT EDIT.
package zodb_test
func init() {
ztestdataReg.Register("py2_pickle3", "testdata/py2_pickle3", nil)
}
// Code generated by py/pydata-gen-testdata; DO NOT EDIT.
package zodb_test
func init() {
ztestdataReg.Register("py3_pickle3", "testdata/py3_pickle3", nil)
}
// Code generated by py/pydata-gen-testdata; DO NOT EDIT.
package zodb
func init() {
_PyDataClassName_TestDataRegistry["py2_pickle1"] = []_PyDataClassName_TestEntry{
{
"((U\x18ZODB.tests.testSerializeq\x01U\x13ClassWithoutNewargsq\x02tNtq\x03.",
"ZODB.tests.testSerialize.ClassWithoutNewargs",
},
{
"((U\x18ZODB.tests.testSerializeq\x01U\x10ClassWithNewargsq\x02t(K\x01tq\x03tq\x04.",
"ZODB.tests.testSerialize.ClassWithNewargs",
},
{
"cZODB.tests.testSerialize\nClassWithoutNewargs\nq\x01.",
"ZODB.tests.testSerialize.ClassWithoutNewargs",
},
{
"(cZODB.tests.testSerialize\nClassWithNewargs\nq\x01(K\x01tq\x02tq\x03.",
"ZODB.tests.testSerialize.ClassWithNewargs",
},
{"aaa", "?.?"},
}
}
// Code generated by py/pydata-gen-testdata; DO NOT EDIT.
package zodb
func init() {
_PyDataClassName_TestDataRegistry["py2_pickle2"] = []_PyDataClassName_TestEntry{
{
"\x80\x02U\x18ZODB.tests.testSerializeq\x01U\x13ClassWithoutNewargsq\x02\x86N\x86q\x03.",
"ZODB.tests.testSerialize.ClassWithoutNewargs",
},
{
"\x80\x02U\x18ZODB.tests.testSerializeq\x01U\x10ClassWithNewargsq\x02\x86K\x01\x85q\x03\x86q\x04.",
"ZODB.tests.testSerialize.ClassWithNewargs",
},
{
"\x80\x02cZODB.tests.testSerialize\nClassWithoutNewargs\nq\x01.",
"ZODB.tests.testSerialize.ClassWithoutNewargs",
},
{
"\x80\x02cZODB.tests.testSerialize\nClassWithNewargs\nq\x01K\x01\x85q\x02\x86q\x03.",
"ZODB.tests.testSerialize.ClassWithNewargs",
},
{"aaa", "?.?"},
}
}
// Code generated by py/pydata-gen-testdata; DO NOT EDIT.
package zodb
func init() {
_PyDataClassName_TestDataRegistry["py2_pickle3"] = []_PyDataClassName_TestEntry{
{
"\x80\x03U\x18ZODB.tests.testSerializeq\x01U\x13ClassWithoutNewargsq\x02\x86N\x86q\x03.",
"ZODB.tests.testSerialize.ClassWithoutNewargs",
},
{
"\x80\x03U\x18ZODB.tests.testSerializeq\x01U\x10ClassWithNewargsq\x02\x86K\x01\x85q\x03\x86q\x04.",
"ZODB.tests.testSerialize.ClassWithNewargs",
},
{
"\x80\x03cZODB.tests.testSerialize\nClassWithoutNewargs\nq\x01.",
"ZODB.tests.testSerialize.ClassWithoutNewargs",
},
{
"\x80\x03cZODB.tests.testSerialize\nClassWithNewargs\nq\x01K\x01\x85q\x02\x86q\x03.",
"ZODB.tests.testSerialize.ClassWithNewargs",
},
{"aaa", "?.?"},
}
}
// Code generated by py/pydata-gen-testdata; DO NOT EDIT.
package zodb
func init() {
_PyDataClassName_TestDataRegistry["py3_pickle3"] = []_PyDataClassName_TestEntry{
{
"\x80\x03X\x18\x00\x00\x00ZODB.tests.testSerializeq\x00X\x13\x00\x00\x00ClassWithoutNewargsq\x01\x86q\x02N\x86q\x03.",
"ZODB.tests.testSerialize.ClassWithoutNewargs",
},
{
"\x80\x03X\x18\x00\x00\x00ZODB.tests.testSerializeq\x00X\x10\x00\x00\x00ClassWithNewargsq\x01\x86q\x02K\x01\x85q\x03\x86q\x04.",
"ZODB.tests.testSerialize.ClassWithNewargs",
},
{
"\x80\x03cZODB.tests.testSerialize\nClassWithoutNewargs\nq\x00.",
"ZODB.tests.testSerialize.ClassWithoutNewargs",
},
{
"\x80\x03cZODB.tests.testSerialize\nClassWithNewargs\nq\x00K\x01\x85q\x01\x86q\x02.",
"ZODB.tests.testSerialize.ClassWithNewargs",
},
{"aaa", "?.?"},
}
}
// Code generated by ./py/pydata-gen-testdata; DO NOT EDIT.
package zodb
var _PyData_ClassName_Testv = [...]_PyDataClassName_TestEntry{
{
"\x80\x02U\x18ZODB.tests.testSerializeq\x01U\x13ClassWithoutNewargsq\x02\x86N\x86q\x03.",
"ZODB.tests.testSerialize.ClassWithoutNewargs",
},
{
"\x80\x02U\x18ZODB.tests.testSerializeq\x01U\x10ClassWithNewargsq\x02\x86K\x01\x85q\x03\x86q\x04.",
"ZODB.tests.testSerialize.ClassWithNewargs",
},
{
"\x80\x02cZODB.tests.testSerialize\nClassWithoutNewargs\nq\x01.",
"ZODB.tests.testSerialize.ClassWithoutNewargs",
},
{
"\x80\x02cZODB.tests.testSerialize\nClassWithNewargs\nq\x01K\x01\x85q\x02\x86q\x03.",
"ZODB.tests.testSerialize.ClassWithNewargs",
},
{"aaa", "?.?"},
}
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