test_docker_execution.py 6.83 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
92
93
94
    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)
        self.host.rm(builder_container)
        assert status == 0

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

103

104
    @slow
105
    @skipif(not DOCKER_NETWORK_TEST_ENABLED, "Network test disabled")
106
107
108
109
110
    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
111

112
113
114
115
116
117
118
    @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

119
120
121
122
123
124
125
    @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)'"

126
127
128
129
130
131
    @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)'"
132

133
134
135
136
    # 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
137
138
139
140

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

143
144
145
146
147
148
        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()
149
150
        self.build_algorithm("prefix/algorithms/user/cxx_integers_echo_sequential")

151
152
153
154
155
        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()
156
157
        self.build_algorithm("prefix/algorithms/user/cxx_integers_echo_autonomous")

158
159
160
161
162
        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()
163
164
165
166
167
168
169
170
        needed_alorithms = [
            "cxx_integers_echo_sequential",
            "cxx_integers_echo_analyzer"
        ]

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

171

172
173
174
175
        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']