• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2"""Test LZ4 interoperability between versions"""
3
4#
5# Copyright (C) 2011-present, Takayuki Matsuoka
6# All rights reserved.
7# GPL v2 License
8#
9
10import glob
11import subprocess
12import filecmp
13import os
14import shutil
15import sys
16import hashlib
17
18repo_url = 'https://github.com/lz4/lz4.git'
19tmp_dir_name = 'tests/abiTests'
20env_flags = ' ' # '-j MOREFLAGS="-g -O0 -fsanitize=address"'
21make_cmd = 'make'
22git_cmd = 'git'
23test_dat_src = ['README.md']
24head = 'v999'
25
26def proc(cmd_args, pipe=True, env=False):
27    if env == False:
28        env = os.environ.copy()
29    if pipe:
30        s = subprocess.Popen(cmd_args,
31                             stdout=subprocess.PIPE,
32                             stderr=subprocess.PIPE,
33                             env = env)
34    else:
35        s = subprocess.Popen(cmd_args, env = env)
36    r = s.communicate()
37    if s.poll() != 0:
38        print(' s.poll() = ', s.poll())
39        sys.exit(1)
40    return r
41
42def make(args, pipe=True, env=False):
43    if env == False:
44        env = os.environ.copy()
45        # we want the address sanitizer for abi tests
46        env["MOREFLAGS"] = "-fsanitize=address"
47    return proc([make_cmd] + ['-j'] + ['V=1'] + args, pipe, env)
48
49def git(args, pipe=True):
50    return proc([git_cmd] + args, pipe)
51
52def get_git_tags():
53    # Only start from first v1.7.x format release
54    stdout, stderr = git(['tag', '-l', 'v[1-9].[0-9].[0-9]'])
55    tags = stdout.decode('utf-8').split()
56    return tags
57
58# https://stackoverflow.com/a/19711609/2132223
59def sha1_of_file(filepath):
60    with open(filepath, 'rb') as f:
61        return hashlib.sha1(f.read()).hexdigest()
62
63if __name__ == '__main__':
64    error_code = 0
65    base_dir = os.getcwd() + '/..'           # /path/to/lz4
66    tmp_dir = base_dir + '/' + tmp_dir_name  # /path/to/lz4/tests/versionsTest
67    clone_dir = tmp_dir + '/' + 'lz4'        # /path/to/lz4/tests/versionsTest/lz4
68    lib_dir = base_dir + '/lib'              # /path/to/lz4/lib
69    test_dir = base_dir + '/tests'
70    os.makedirs(tmp_dir, exist_ok=True)
71
72    # since Travis clones limited depth, we should clone full repository
73    if not os.path.isdir(clone_dir):
74        git(['clone', repo_url, clone_dir])
75
76    # Retrieve all release tags
77    print('Retrieve release tags >= v1.7.5 :')
78    os.chdir(clone_dir)
79    tags = [head] + get_git_tags()
80    tags = [x for x in tags if (x >= 'v1.7.5')]
81    print(tags)
82
83    # loop across architectures
84    for march in ['-m64', '-m32', '-mx32']:
85        print(' ')
86        print('=====================================')
87        print('Testing architecture ' + march);
88        print('=====================================')
89
90        # Build all versions of liblz4
91        # note : naming scheme only works on Linux
92        for tag in tags:
93            print('building library ', tag)
94            os.chdir(base_dir)
95    #        if not os.path.isfile(dst_liblz4) or tag == head:
96            if tag != head:
97                r_dir = '{}/{}'.format(tmp_dir, tag)  # /path/to/lz4/test/lz4test/<TAG>
98                #print('r_dir = ', r_dir)  # for debug
99                os.makedirs(r_dir, exist_ok=True)
100                os.chdir(clone_dir)
101                git(['--work-tree=' + r_dir, 'checkout', tag, '--', '.'])
102                os.chdir(r_dir + '/lib')  # /path/to/lz4/lz4test/<TAG>/lib
103            else:
104                # print('lib_dir = {}', lib_dir)  # for debug
105                os.chdir(lib_dir)
106            make(['clean'])
107            build_env = os.environ.copy()
108            build_env["CFLAGS"] = march
109            build_env["MOREFLAGS"] = "-fsanitize=address"
110            make(['liblz4'], env=build_env)
111
112        print(' ')
113        print('******************************')
114        print('Round trip expecting current ABI but linking to older Dynamic Library version')
115        print('******************************')
116        os.chdir(test_dir)
117        # Start with matching version : should be no problem
118        build_env = os.environ.copy()
119        build_env["CFLAGS"] = march
120        build_env["LDFLAGS"] = "-L../lib"
121        build_env["LDLIBS"] = "-llz4"
122        # we use asan to detect any out-of-bound read or write
123        build_env["MOREFLAGS"] = "-fsanitize=address"
124        if os.path.isfile('abiTest'):
125            os.remove('abiTest')
126        make(['abiTest'], env=build_env, pipe=False)
127
128        for tag in tags:
129            print('linking to lib tag = ', tag)
130            run_env = os.environ.copy()
131            if tag == head:
132                run_env["LD_LIBRARY_PATH"] = '../lib'
133            else:
134                run_env["LD_LIBRARY_PATH"] = 'abiTests/{}/lib'.format(tag)
135            # check we are linking to the right library version at run time
136            proc(['./check_liblz4_version.sh'] + ['./abiTest'], pipe=False, env=run_env)
137            # now run with mismatched library version
138            proc(['./abiTest'] + test_dat_src, pipe=False, env=run_env)
139
140        print(' ')
141        print('******************************')
142        print('Round trip using current Dynamic Library expecting older ABI version')
143        print('******************************')
144
145        for tag in tags:
146            print(' ')
147            print('building using older lib ', tag)
148            build_env = os.environ.copy()
149            if tag != head:
150                build_env["CPPFLAGS"] = '-IabiTests/{}/lib'.format(tag)
151                build_env["LDFLAGS"] = '-LabiTests/{}/lib'.format(tag)
152            else:
153                build_env["CPPFLAGS"] = '-I../lib'
154                build_env["LDFLAGS"] = '-L../lib'
155            build_env["LDLIBS"] = "-llz4"
156            build_env["CFLAGS"] = march
157            build_env["MOREFLAGS"] = "-fsanitize=address"
158            os.remove('abiTest')
159            make(['abiTest'], pipe=False, env=build_env)
160
161            print('run with CURRENT library version (head)')
162            run_env = os.environ.copy()
163            run_env["LD_LIBRARY_PATH"] = '../lib'
164            # check we are linking to the right library version at run time
165            proc(['./check_liblz4_version.sh'] + ['./abiTest'], pipe=False, env=run_env)
166            # now run with mismatched library version
167            proc(['./abiTest'] + test_dat_src, pipe=False, env=run_env)
168
169
170    if error_code != 0:
171        print('ERROR')
172
173    sys.exit(error_code)
174