~longsleep/snapcraft/snapcraft-debs-plugin

« back to all changes in this revision

Viewing changes to snapcraft/tests/test_yaml.py

  • Committer: Snappy Tarmac
  • Author(s): Sergio Schvezov
  • Date: 2015-08-27 22:11:32 UTC
  • mfrom: (134.4.11 validation)
  • Revision ID: snappy_tarmac-20150827221132-b8b8au821wrnjyxt
Initial json schema support by sergiusens approved by chipaca,elopio

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# You should have received a copy of the GNU General Public License
15
15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
16
 
 
17
import jsonschema
17
18
import logging
18
19
import os
19
20
import tempfile
20
21
import unittest
 
22
import unittest.mock
21
23
 
22
24
import fixtures
23
25
 
 
26
import snapcraft.common
 
27
import snapcraft.yaml
24
28
from snapcraft import dirs
25
 
from snapcraft.yaml import Config
26
29
from snapcraft.tests import TestCase
27
30
 
28
31
 
37
40
 
38
41
    @unittest.mock.patch('snapcraft.yaml.Config.load_plugin')
39
42
    def test_config_loads_plugins(self, mock_loadPlugin):
40
 
        self.make_snapcraft_yaml("""parts:
 
43
        dirs.setup_dirs()
 
44
 
 
45
        self.make_snapcraft_yaml("""name: test
 
46
version: "1"
 
47
vendor: me <me@me.com>
 
48
summary: test
 
49
description: test
 
50
 
 
51
parts:
41
52
  ubuntu:
42
53
    packages: [fswebcam]
43
54
""")
44
 
        Config()
 
55
        snapcraft.yaml.Config()
45
56
        mock_loadPlugin.assert_called_with("ubuntu", "ubuntu", {
46
57
            "packages": ["fswebcam"],
47
58
        })
52
63
 
53
64
        # no snapcraft.yaml
54
65
        with self.assertRaises(SystemExit) as raised:
55
 
            Config()
 
66
            snapcraft.yaml.Config()
56
67
 
57
68
        self.assertEqual(raised.exception.code, 1, 'Wrong exit code returned.')
58
69
        self.assertEqual(
66
77
        fake_logger = fixtures.FakeLogger(level=logging.ERROR)
67
78
        self.useFixture(fake_logger)
68
79
 
69
 
        self.make_snapcraft_yaml("""parts:
 
80
        self.make_snapcraft_yaml("""name: test
 
81
version: "1"
 
82
vendor: me <me@me.com>
 
83
summary: test
 
84
description: test
 
85
 
 
86
parts:
70
87
  p1:
71
88
    plugin: ubuntu
72
89
    after: [p2]
75
92
    after: [p1]
76
93
""")
77
94
        with self.assertRaises(SystemExit) as raised:
78
 
            Config()
 
95
            snapcraft.yaml.Config()
79
96
 
80
97
        self.assertEqual(raised.exception.code, 1, 'Wrong exit code returned.')
81
98
        self.assertEqual('Circular dependency chain!\n', fake_logger.output)
 
99
 
 
100
    @unittest.mock.patch('snapcraft.yaml.Config.load_plugin')
 
101
    def test_invalid_yaml_missing_name(self, mock_loadPlugin):
 
102
        dirs.setup_dirs()
 
103
 
 
104
        fake_logger = fixtures.FakeLogger(level=logging.ERROR)
 
105
        self.useFixture(fake_logger)
 
106
 
 
107
        self.make_snapcraft_yaml("""
 
108
version: "1"
 
109
vendor: me <me@me.com>
 
110
summary: test
 
111
description: nothing
 
112
 
 
113
parts:
 
114
  ubuntu:
 
115
    packages: [fswebcam]
 
116
""")
 
117
        with self.assertRaises(SystemExit) as raised:
 
118
            snapcraft.yaml.Config()
 
119
 
 
120
        self.assertEqual(raised.exception.code, 1, 'Wrong exit code returned.')
 
121
        self.assertEqual(
 
122
            'Issues while validating snapcraft.yaml: \'name\' is a required property\n',
 
123
            fake_logger.output)
 
124
 
 
125
    @unittest.mock.patch('snapcraft.yaml.Config.load_plugin')
 
126
    def test_invalid_yaml_invalid_name_as_number(self, mock_loadPlugin):
 
127
        dirs.setup_dirs()
 
128
 
 
129
        fake_logger = fixtures.FakeLogger(level=logging.ERROR)
 
130
        self.useFixture(fake_logger)
 
131
 
 
132
        self.make_snapcraft_yaml("""name: 1
 
133
version: "1"
 
134
vendor: me <me@me.com>
 
135
summary: test
 
136
description: nothing
 
137
 
 
138
parts:
 
139
  ubuntu:
 
140
    packages: [fswebcam]
 
141
""")
 
142
        with self.assertRaises(SystemExit) as raised:
 
143
            snapcraft.yaml.Config()
 
144
 
 
145
        self.assertEqual(raised.exception.code, 1, 'Wrong exit code returned.')
 
146
        self.assertEqual(
 
147
            'Issues while validating snapcraft.yaml: 1 is not of type \'string\'\n',
 
148
            fake_logger.output)
 
149
 
 
150
    @unittest.mock.patch('snapcraft.yaml.Config.load_plugin')
 
151
    def test_invalid_yaml_invalid_name_chars(self, mock_loadPlugin):
 
152
        dirs.setup_dirs()
 
153
 
 
154
        fake_logger = fixtures.FakeLogger(level=logging.ERROR)
 
155
        self.useFixture(fake_logger)
 
156
 
 
157
        self.make_snapcraft_yaml("""name: myapp@me_1.0
 
158
version: "1"
 
159
vendor: me <me@me.com>
 
160
summary: test
 
161
description: nothing
 
162
 
 
163
parts:
 
164
  ubuntu:
 
165
    packages: [fswebcam]
 
166
""")
 
167
        with self.assertRaises(SystemExit) as raised:
 
168
            snapcraft.yaml.Config()
 
169
 
 
170
        self.assertEqual(raised.exception.code, 1, 'Wrong exit code returned.')
 
171
        self.assertEqual(
 
172
            'Issues while validating snapcraft.yaml: \'myapp@me_1.0\' does not match \'^[a-z0-9][a-z0-9+-]*$\'\n',
 
173
            fake_logger.output)
 
174
 
 
175
    @unittest.mock.patch('snapcraft.yaml.Config.load_plugin')
 
176
    def test_invalid_yaml_missing_description(self, mock_loadPlugin):
 
177
        dirs.setup_dirs()
 
178
 
 
179
        fake_logger = fixtures.FakeLogger(level=logging.ERROR)
 
180
        self.useFixture(fake_logger)
 
181
 
 
182
        self.make_snapcraft_yaml("""name: test
 
183
version: "1"
 
184
vendor: me <me@me.com>
 
185
summary: test
 
186
 
 
187
parts:
 
188
  ubuntu:
 
189
    packages: [fswebcam]
 
190
""")
 
191
        with self.assertRaises(SystemExit) as raised:
 
192
            snapcraft.yaml.Config()
 
193
 
 
194
        self.assertEqual(raised.exception.code, 1, 'Wrong exit code returned.')
 
195
        self.assertEqual(
 
196
            'Issues while validating snapcraft.yaml: \'description\' is a required property\n',
 
197
            fake_logger.output)
 
198
 
 
199
 
 
200
class TestValidation(TestCase):
 
201
 
 
202
    def setUp(self):
 
203
        super().setUp()
 
204
        dirs.setup_dirs()
 
205
 
 
206
        self.data = {
 
207
            'name': 'my-package-1',
 
208
            'version': '1.0-snapcraft1~ppa1',
 
209
            'vendor': 'Me <me@me.com>',
 
210
            'summary': 'my summary less that 79 chars',
 
211
            'description': 'description which can be pretty long',
 
212
            'parts': {
 
213
                'part1': {
 
214
                    'type': 'project',
 
215
                },
 
216
            },
 
217
        }
 
218
 
 
219
    def test_required_properties(self):
 
220
        for key in self.data:
 
221
            data = self.data.copy()
 
222
            with self.subTest(key=key):
 
223
                del data[key]
 
224
 
 
225
                with self.assertRaises(jsonschema.ValidationError) as raised:
 
226
                    snapcraft.yaml._validate_snapcraft_yaml(data)
 
227
 
 
228
                expected_message = '\'{}\' is a required property'.format(key)
 
229
                self.assertEqual(raised.exception.message, expected_message, msg=data)
 
230
 
 
231
    def test_invalid_names(self):
 
232
        invalid_names = [
 
233
            'package@awesome',
 
234
            'something.another',
 
235
            '_hideme',
 
236
        ]
 
237
 
 
238
        for name in invalid_names:
 
239
            data = self.data.copy()
 
240
            with self.subTest(key=name):
 
241
                data['name'] = name
 
242
 
 
243
                with self.assertRaises(jsonschema.ValidationError) as raised:
 
244
                    snapcraft.yaml._validate_snapcraft_yaml(data)
 
245
 
 
246
                expected_message = '\'{}\' does not match \'^[a-z0-9][a-z0-9+-]*$\''.format(name)
 
247
                self.assertEqual(raised.exception.message, expected_message, msg=data)
 
248
 
 
249
    def test_summary_too_long(self):
 
250
        self.data['summary'] = 'a' * 80
 
251
        with self.assertRaises(jsonschema.ValidationError) as raised:
 
252
            snapcraft.yaml._validate_snapcraft_yaml(self.data)
 
253
 
 
254
        expected_message = '\'{}\' is too long'.format(self.data['summary'])
 
255
        self.assertEqual(raised.exception.message, expected_message, msg=self.data)
 
256
 
 
257
    def test_valid_types(self):
 
258
        self.data['type'] = 'app'
 
259
        snapcraft.yaml._validate_snapcraft_yaml(self.data)
 
260
 
 
261
        self.data['type'] = 'framework'
 
262
        snapcraft.yaml._validate_snapcraft_yaml(self.data)
 
263
 
 
264
    def test_invalid_types(self):
 
265
        invalid_types = [
 
266
            'apps',
 
267
            'kernel',
 
268
            'platform',
 
269
            'oem',
 
270
            'os',
 
271
        ]
 
272
 
 
273
        for t in invalid_types:
 
274
            data = self.data.copy()
 
275
            with self.subTest(key=t):
 
276
                data['type'] = t
 
277
 
 
278
                with self.assertRaises(jsonschema.ValidationError) as raised:
 
279
                    snapcraft.yaml._validate_snapcraft_yaml(data)
 
280
 
 
281
                expected_message = '\'{}\' is not one of [\'app\', \'framework\']'.format(t)
 
282
                self.assertEqual(raised.exception.message, expected_message, msg=data)
 
283
 
 
284
    def test_valid_services(self):
 
285
        self.data['services'] = [
 
286
            {
 
287
                'name': 'service1',
 
288
                'start': 'binary1 start',
 
289
            },
 
290
            {
 
291
                'name': 'service2',
 
292
                'start': 'binary2',
 
293
                'stop': 'binary2 --stop',
 
294
            },
 
295
            {
 
296
                'name': 'service3',
 
297
            }
 
298
        ]
 
299
 
 
300
        snapcraft.yaml._validate_snapcraft_yaml(self.data)
 
301
 
 
302
    def test_services_required_properties(self):
 
303
        self.data['services'] = [
 
304
            {
 
305
                'start': 'binary1 start',
 
306
            }
 
307
        ]
 
308
 
 
309
        with self.assertRaises(jsonschema.ValidationError) as raised:
 
310
            snapcraft.yaml._validate_snapcraft_yaml(self.data)
 
311
 
 
312
        expected_message = '\'name\' is a required property'
 
313
        self.assertEqual(raised.exception.message, expected_message, msg=self.data)
 
314
 
 
315
    def test_schema_file_not_found(self):
 
316
        mock_the_open = unittest.mock.mock_open()
 
317
        mock_the_open.side_effect = FileNotFoundError()
 
318
 
 
319
        with unittest.mock.patch('snapcraft.yaml.open', mock_the_open, create=True):
 
320
            with self.assertRaises(snapcraft.yaml.SchemaNotFoundError) as raised:
 
321
                snapcraft.yaml._validate_snapcraft_yaml(self.data)
 
322
 
 
323
        expected_path = os.path.join(snapcraft.common.get_schemadir(), 'snapcraft.yaml')
 
324
        mock_the_open.assert_called_once_with(expected_path)
 
325
        expected_message = 'Schema is missing, could not validate snapcraft.yaml, check installation'
 
326
        self.assertEqual(raised.exception.message, expected_message)