test_docker_execution.py 6.91 KB
Newer Older
1
2
3
4
5
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :

###############################################################################
#                                                                             #
6
# Copyright (c) 2016 Idiap Research Institute, http://www.idiap.ch/           #
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# Contact: beat.support@idiap.ch                                              #
#                                                                             #
# This file is part of the beat.core module of the BEAT platform.             #
#                                                                             #
# Commercial License Usage                                                    #
# Licensees holding valid commercial BEAT licenses may use this file in       #
# accordance with the terms contained in a written agreement between you      #
# and Idiap. For further information contact tto@idiap.ch                     #
#                                                                             #
# Alternatively, this file may be used under the terms of the GNU Affero      #
# Public License version 3 as published by the Free Software and appearing    #
# in the file LICENSE.AGPL included in the packaging of this file.            #
# The BEAT platform is distributed in the hope that it will be useful, but    #
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY  #
# or FITNESS FOR A PARTICULAR PURPOSE.                                        #
#                                                                             #
# You should have received a copy of the GNU Affero Public License along      #
# with the BEAT platform. If not, see http://www.gnu.org/licenses/.           #
#                                                                             #
###############################################################################

28
29

# Tests for experiment execution within Docker containers
30

31
import os
32
import subprocess
33

34
from ..dock import Host
35
36
from ..execution import DockerExecutor

37
from .utils import cleanup
38
from .utils import slow
39
from .utils import skipif
40

41
from .test_execution import BaseExecutionMixIn
42

43
from . import network_name
44
from . import prefix_folder
45
from . import DOCKER_NETWORK_TEST_ENABLED
46

47
48
BUILDER_IMAGE = "docker.idiap.ch/beat/beat.env.client:2.0.0r0"

49
#----------------------------------------------------------
50
51


52
class TestDockerExecution(BaseExecutionMixIn):
53

54
    @classmethod
55
    def setup_class(cls):
56
57
58
59
        cls.host = Host(raise_on_errors=False)


    @classmethod
60
    def teardown_class(cls):
61
62
        cls.host.teardown()
        cleanup()
63
64


65
    def teardown(self):
66
67
68
        self.host.teardown()


69
70
    def create_executor(self, prefix, configuration, tmp_prefix, dataformat_cache,
                        database_cache, algorithm_cache):
71
72
73
74
75
76
        executor = DockerExecutor(self.host, prefix, configuration, tmp_prefix,
                                  dataformat_cache, database_cache, algorithm_cache)

        executor.debug = os.environ.get("DOCKER_TEST_DEBUG", False) == "True"
        return executor

77

78
79
80
81
82
83
84
85
86
87
88
89
90
91
    def build_algorithm(self, algorithm):
        test_folder = os.path.abspath(os.path.join(os.path.dirname(__file__)))
        scripts_folder = os.path.abspath(os.path.join(test_folder, '../../../'))
        sources_folder = os.path.abspath(os.path.join(test_folder, algorithm))
        cmd = ['/build.sh']
        builder_container = self.host.create_container(BUILDER_IMAGE, cmd)
        builder_container.add_volume("%s/scripts/build.sh" % scripts_folder, "/build.sh")
        builder_container.add_volume(sources_folder, "/sources", read_only=False)
        builder_container.uid = os.getuid()
        builder_container.set_workdir("/sources")
        builder_container.set_entrypoint("bash")

        self.host.start(builder_container)
        status = self.host.wait(builder_container)
92
93
94
        if status != 0:
            print(self.host.logs(builder_container))

95
96
97
        self.host.rm(builder_container)
        assert status == 0

98
99
100
101
102
103
104
105
        # Update the tmp prefix with the latest content
        subprocess.check_call(['rsync',
                               '-arz',
                               '--exclude="*"',
                               '--include="*.so"',
                               os.path.join(test_folder, 'prefix'),
                               prefix_folder])

106

107
    @slow
108
    @skipif(not DOCKER_NETWORK_TEST_ENABLED, "Network test disabled")
109
110
111
112
113
    def test_custom_network(self):
        result = self.execute('user/user/integers_addition/1/integers_addition',
                [{'sum': 495, 'nb': 9}], network_name=network_name)

        assert result is None
114

115
116
117
118
119
120
121
    @slow
    def test_custom_port_range(self):
        result = self.execute('user/user/integers_addition/1/integers_addition',
                [{'sum': 495, 'nb': 9}], port_range="50000:50100")

        assert result is None

122
123
124
125
126
127
128
    @slow
    def test_single_1_prepare_error(self):
        result = self.execute('user/user/single/1/prepare_error', [None])

        assert result['status'] == 1
        assert result['user_error'] == "'Could not prepare algorithm (returned False)'"

129
130
131
132
133
134
    @slow
    def test_single_1_setup_error(self):
        result = self.execute('user/user/single/1/setup_error', [None])

        assert result['status'] == 1
        assert result['user_error'] == "'Could not setup algorithm (returned False)'"
135

136
137
138
139
    # NOT COMPATIBLE YET WITH THE NEW API
    # @slow
    # def test_cxx_double_1(self):
    #     assert self.execute('user/user/double/1/cxx_double', [{'out_data': 42}]) is None
140
141
142
143

    @slow
    def test_cxx_double_legacy(self):
        datasets_uid = os.getuid()
144
145
        self.build_algorithm("prefix/algorithms/user/cxx_integers_echo_legacy")

146
147
148
149
150
151
        result = self.execute('user/user/double/1/cxx_double_legacy', [{'out_data': 42}], datasets_uid=datasets_uid)
        assert result is None

    @slow
    def test_cxx_double_sequential(self):
        datasets_uid = os.getuid()
152
153
        self.build_algorithm("prefix/algorithms/user/cxx_integers_echo_sequential")

154
155
156
157
158
        assert self.execute('user/user/double/1/cxx_double_sequential', [{'out_data': 42}], datasets_uid=datasets_uid) is None

    @slow
    def test_cxx_double_autonomous(self):
        datasets_uid = os.getuid()
159
160
        self.build_algorithm("prefix/algorithms/user/cxx_integers_echo_autonomous")

161
162
163
164
165
        assert self.execute('user/user/double/1/cxx_double_autonomous', [{'out_data': 42}], datasets_uid=datasets_uid) is None

    @slow
    def test_cxx_analyzer_error(self):
        datasets_uid = os.getuid()
166
167
168
169
170
171
172
173
        needed_alorithms = [
            "cxx_integers_echo_sequential",
            "cxx_integers_echo_analyzer"
        ]

        for algorithm in needed_alorithms:
            self.build_algorithm("prefix/algorithms/user/%s" % algorithm)

174

175
176
177
178
        result = self.execute('user/user/double/1/cxx_analyzer_error', [{'out_data': 42}], datasets_uid=datasets_uid)

        assert result['status'] == 255
        assert "[sys] C++ algorithm can't be analyzers" in result['stderr']