SHA256
1
0
forked from pool/salt
salt/fix-regression-in-file.get_managed-add-unit-tests.patch

197 lines
6.8 KiB
Diff

From 89fd1a83d282a10728077a08466627271a052733 Mon Sep 17 00:00:00 2001
From: Erik Johnson <palehose@gmail.com>
Date: Wed, 1 Mar 2017 10:19:33 -0600
Subject: [PATCH] Fix regression in file.get_managed, add unit tests
This is no longer needed since we're invoking the state module directly
and not via the state compiler.
* Fix regression in file.get_managed when skip_verify=True
* Add integration tests for remote file sources
* Remove next(iter()) extraction
---
salt/modules/file.py | 6 +--
salt/states/archive.py | 11 ----
tests/integration/states/file.py | 105 +++++++++++++++++++++++++++++++++++++++
3 files changed, 108 insertions(+), 14 deletions(-)
diff --git a/salt/modules/file.py b/salt/modules/file.py
index 8f0c6914b6..381800bc1a 100644
--- a/salt/modules/file.py
+++ b/salt/modules/file.py
@@ -3745,13 +3745,13 @@ def get_managed(
if cached_dest and (source_hash or skip_verify):
htype = source_sum.get('hash_type', 'sha256')
cached_sum = get_hash(cached_dest, form=htype)
- if cached_sum != source_sum['hsum']:
- cache_refetch = True
- elif skip_verify:
+ if skip_verify:
# prev: if skip_verify or cached_sum == source_sum['hsum']:
# but `cached_sum == source_sum['hsum']` is elliptical as prev if
sfn = cached_dest
source_sum = {'hsum': cached_sum, 'hash_type': htype}
+ elif cached_sum != source_sum['hsum']:
+ cache_refetch = True
# If we didn't have the template or remote file, let's get it
# Similarly when the file has been updated and the cache has to be refreshed
diff --git a/salt/states/archive.py b/salt/states/archive.py
index c5df213620..46146e971e 100644
--- a/salt/states/archive.py
+++ b/salt/states/archive.py
@@ -897,17 +897,6 @@ def extracted(name,
ret['comment'] = '\n'.join([str(x) for x in file_result])
return ret
- # Get actual state result. The state.single return is a single-element
- # dictionary with the state's unique ID at the top level, and its value
- # being the state's return dictionary. next(iter(dict_name)) will give
- # us the value of the first key, so
- # file_result[next(iter(file_result))] will give us the results of the
- # state.single we just ran.
- try:
- file_result = file_result[next(iter(file_result))]
- except AttributeError:
- pass
-
try:
if not file_result['result']:
log.debug('failed to download {0}'.format(source_match))
diff --git a/tests/integration/states/file.py b/tests/integration/states/file.py
index d63f318064..faa83d00e8 100644
--- a/tests/integration/states/file.py
+++ b/tests/integration/states/file.py
@@ -9,15 +9,22 @@ from __future__ import absolute_import
from distutils.version import LooseVersion
import errno
import glob
+import logging
import os
import re
import sys
import shutil
+import socket
import stat
import tempfile
import textwrap
+import threading
+import tornado.ioloop
+import tornado.web
import filecmp
+log = logging.getLogger(__name__)
+
# Import 3rd-party libs
from salt.ext.six.moves import range # pylint: disable=import-error,redefined-builtin
@@ -2392,6 +2399,104 @@ class FileTest(integration.ModuleCase, integration.SaltReturnAssertsMixIn):
if check_file:
self.run_function('file.remove', [file])
+
+PORT = 9999
+FILE_SOURCE = 'http://localhost:{0}/grail/scene33'.format(PORT)
+FILE_HASH = 'd2feb3beb323c79fc7a0f44f1408b4a3'
+STATE_DIR = os.path.join(integration.FILES, 'file', 'base')
+
+
+class RemoteFileTest(integration.ModuleCase, integration.SaltReturnAssertsMixIn):
+ '''
+ Uses a local tornado webserver to test http(s) file.managed states with and
+ without skip_verify
+ '''
+ @classmethod
+ def webserver(cls):
+ '''
+ method to start tornado static web app
+ '''
+ application = tornado.web.Application([
+ (r'/(.*)', tornado.web.StaticFileHandler, {'path': STATE_DIR})
+ ])
+ application.listen(PORT)
+ tornado.ioloop.IOLoop.instance().start()
+
+ @classmethod
+ def setUpClass(cls):
+ '''
+ start tornado app on thread and wait until it is running
+ '''
+ cls.server_thread = threading.Thread(target=cls.webserver)
+ cls.server_thread.daemon = True
+ cls.server_thread.start()
+ # check if tornado app is up
+ port_closed = True
+ while port_closed:
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ result = sock.connect_ex(('127.0.0.1', PORT))
+ if result == 0:
+ port_closed = False
+
+ @classmethod
+ def tearDownClass(cls):
+ tornado.ioloop.IOLoop.instance().stop()
+ cls.server_thread.join()
+
+ def setUp(self):
+ fd_, self.name = tempfile.mkstemp(dir=integration.TMP)
+ try:
+ os.close(fd_)
+ except OSError as exc:
+ if exc.errno != errno.EBADF:
+ raise exc
+ # Remove the file that mkstemp just created so that the states can test
+ # creating a new file instead of a diff from a zero-length file.
+ self.tearDown()
+
+ def tearDown(self):
+ try:
+ os.remove(self.name)
+ except OSError as exc:
+ if exc.errno != errno.ENOENT:
+ raise exc
+
+ def test_file_managed_http_source_no_hash(self):
+ '''
+ Test a remote file with no hash
+ '''
+ ret = self.run_state('file.managed',
+ name=self.name,
+ source=FILE_SOURCE,
+ skip_verify=False)
+ log.debug('ret = %s', ret)
+ # This should fail because no hash was provided
+ self.assertSaltFalseReturn(ret)
+
+ def test_file_managed_http_source(self):
+ '''
+ Test a remote file with no hash
+ '''
+ ret = self.run_state('file.managed',
+ name=self.name,
+ source=FILE_SOURCE,
+ source_hash=FILE_HASH,
+ skip_verify=False)
+ log.debug('ret = %s', ret)
+ self.assertSaltTrueReturn(ret)
+
+ def test_file_managed_http_source_skip_verify(self):
+ '''
+ Test a remote file using skip_verify
+ '''
+ ret = self.run_state('file.managed',
+ name=self.name,
+ source=FILE_SOURCE,
+ skip_verify=True)
+ log.debug('ret = %s', ret)
+ self.assertSaltTrueReturn(ret)
+
+
if __name__ == '__main__':
from integration import run_tests
run_tests(FileTest)
--
2.11.0