mirror of
https://github.com/valitydev/salt.git
synced 2024-11-07 17:09:03 +00:00
Merge branch '2017.7' into service_test
This commit is contained in:
commit
716aabc0bf
5
.gitignore
vendored
5
.gitignore
vendored
@ -91,3 +91,8 @@ tests/integration/cloud/providers/pki/minions
|
||||
|
||||
# Ignore tox virtualenvs
|
||||
/.tox/
|
||||
|
||||
# Ignore kitchen stuff
|
||||
.kitchen
|
||||
.bundle
|
||||
Gemfile.lock
|
||||
|
175
.kitchen.yml
Normal file
175
.kitchen.yml
Normal file
@ -0,0 +1,175 @@
|
||||
---
|
||||
<% vagrant = system('which vagrant 2>/dev/null >/dev/null') %>
|
||||
<% version = '2016.11.8' %>
|
||||
<% platformsfile = ENV['SALT_KITCHEN_PLATFORMS'] || '.kitchen/platforms.yml' %>
|
||||
<% driverfile = ENV['SALT_KITCHEN_DRIVER'] || '.kitchen/driver.yml' %>
|
||||
|
||||
<% if File.exists?(driverfile) %>
|
||||
<%= File.read(driverfile) %>
|
||||
<% else %>
|
||||
driver:
|
||||
name: docker
|
||||
use_sudo: false
|
||||
privileged: true
|
||||
username: root
|
||||
volume:
|
||||
- /var/run/docker.sock:/docker.sock
|
||||
cap_add:
|
||||
- sys_admin
|
||||
disable_upstart: false
|
||||
provision_command:
|
||||
- echo 'L /run/docker.sock - - - - /docker.sock' > /etc/tmpfiles.d/docker.conf
|
||||
<% end %>
|
||||
|
||||
sudo: false
|
||||
provisioner:
|
||||
name: salt_solo
|
||||
salt_install: bootstrap
|
||||
salt_version: latest
|
||||
salt_bootstrap_url: https://bootstrap.saltstack.com
|
||||
salt_bootstrap_options: -X stable <%= version %>
|
||||
log_level: info
|
||||
require_chef: false
|
||||
remote_states:
|
||||
name: git://github.com/gtmanfred/salt-jenkins.git
|
||||
branch: 2016.11
|
||||
repo: git
|
||||
testingdir: /testing
|
||||
salt_copy_filter:
|
||||
- .bundle
|
||||
- .git
|
||||
- .gitignore
|
||||
- .kitchen
|
||||
- .kitchen.yml
|
||||
- Gemfile
|
||||
- Gemfile.lock
|
||||
- README.rst
|
||||
- .travis.yml
|
||||
state_top:
|
||||
base:
|
||||
"*":
|
||||
- git.salt
|
||||
- kitchen
|
||||
<% if File.exists?(platformsfile) %>
|
||||
<%= File.read(platformsfile) %>
|
||||
<% else %>
|
||||
platforms:
|
||||
- name: fedora
|
||||
driver_config:
|
||||
image: fedora:latest
|
||||
run_command: /usr/lib/systemd/systemd
|
||||
provisioner:
|
||||
salt_bootstrap_options: -X git v<%= version %> >/dev/null
|
||||
- name: centos-7
|
||||
driver_config:
|
||||
run_command: /usr/lib/systemd/systemd
|
||||
- name: centos-6
|
||||
driver_config:
|
||||
run_command: /sbin/init
|
||||
provision_command:
|
||||
- yum install -y upstart
|
||||
provisioner:
|
||||
salt_bootstrap_options: -P -y -x python2.7 -X git v<%= version %> >/dev/null
|
||||
- name: ubuntu-rolling
|
||||
driver_config:
|
||||
image: ubuntu:rolling
|
||||
run_command: /lib/systemd/systemd
|
||||
provisioner:
|
||||
salt_bootstrap_url: https://raw.githubusercontent.com/saltstack/salt-bootstrap/develop/bootstrap-salt.sh
|
||||
- name: ubuntu-16.04
|
||||
driver_config:
|
||||
run_command: /lib/systemd/systemd
|
||||
- name: ubuntu-14.04
|
||||
driver_config:
|
||||
run_command: /sbin/init
|
||||
provision_command:
|
||||
- rm -f /sbin/initctl
|
||||
- dpkg-divert --local --rename --remove /sbin/initctl
|
||||
- name: debian-8
|
||||
driver_config:
|
||||
run_command: /lib/systemd/systemd
|
||||
provision_command:
|
||||
- apt-get install -y dbus
|
||||
- echo 'L /run/docker.sock - - - - /docker.sock' > /etc/tmpfiles.d/docker.conf
|
||||
- name: debian-9
|
||||
driver_config:
|
||||
run_command: /lib/systemd/systemd
|
||||
- name: arch
|
||||
driver_config:
|
||||
image: base/archlinux
|
||||
run_command: /usr/lib/systemd/systemd
|
||||
provision_command:
|
||||
- pacman -Syu --noconfirm systemd
|
||||
- systemctl enable sshd
|
||||
- echo 'L /run/docker.sock - - - - /docker.sock' > /etc/tmpfiles.d/docker.conf
|
||||
provisioner:
|
||||
salt_bootstrap_options: -X git v<%= version %> >/dev/null
|
||||
- name: opensuse
|
||||
driver_config:
|
||||
run_command: /usr/lib/systemd/systemd
|
||||
provision_command:
|
||||
- systemctl enable sshd.service
|
||||
- echo 'L /run/docker.sock - - - - /docker.sock' > /etc/tmpfiles.d/docker.conf
|
||||
provisioner:
|
||||
salt_bootstrap_options: -X git v<%= version %> >/dev/null
|
||||
<% if vagrant != false %>
|
||||
- name: windows-2012r2
|
||||
driver:
|
||||
box: mwrock/Windows2012R2
|
||||
communicator: winrm
|
||||
name: vagrant
|
||||
gui: true
|
||||
username: administrator
|
||||
password: Pass@word1
|
||||
provisioner:
|
||||
init_environment: |
|
||||
Clear-Host
|
||||
$AddedLocation ="c:\salt"
|
||||
$Reg = "Registry::HKLM\System\CurrentControlSet\Control\Session Manager\Environment"
|
||||
$OldPath = (Get-ItemProperty -Path "$Reg" -Name PATH).Path
|
||||
$NewPath= $OldPath + ’;’ + $AddedLocation
|
||||
Set-ItemProperty -Path "$Reg" -Name PATH –Value $NewPath
|
||||
salt_bootstrap_url: https://raw.githubusercontent.com/saltstack/salt-bootstrap/develop/bootstrap-salt.ps1
|
||||
salt_bootstrap_options: ''
|
||||
- name: windows-2016
|
||||
driver:
|
||||
box: mwrock/Windows2016
|
||||
communicator: winrm
|
||||
name: vagrant
|
||||
username: Vagrant
|
||||
password: vagrant
|
||||
gui: true
|
||||
provisioner:
|
||||
init_environment: |
|
||||
Clear-Host
|
||||
$AddedLocation ="c:\salt;c:\salt\bin\Scripts"
|
||||
$Reg = "Registry::HKLM\System\CurrentControlSet\Control\Session Manager\Environment"
|
||||
$OldPath = (Get-ItemProperty -Path "$Reg" -Name PATH).Path
|
||||
$NewPath= $OldPath + ’;’ + $AddedLocation
|
||||
Set-ItemProperty -Path "$Reg" -Name PATH –Value $NewPath
|
||||
salt_bootstrap_url: https://raw.githubusercontent.com/saltstack/salt-bootstrap/develop/bootstrap-salt.ps1
|
||||
salt_bootstrap_options: ''
|
||||
<% end %>
|
||||
<% end %>
|
||||
suites:
|
||||
- name: py2
|
||||
provisioner:
|
||||
pillars:
|
||||
top.sls:
|
||||
base:
|
||||
"*":
|
||||
- jenkins
|
||||
jenkins.sls:
|
||||
testing_dir: /tmp/kitchen/testing
|
||||
clone_repo: false
|
||||
salttesting_namespec: salttesting==2017.6.1
|
||||
verifier:
|
||||
name: shell
|
||||
remote_exec: true
|
||||
sudo: false
|
||||
live_stream: {}
|
||||
<% if ENV['TESTOPTS'].nil? %>
|
||||
command: '$(kitchen) /tmp/kitchen/testing/tests/runtests.py --run-destructive --sysinfo --transport=zeromq --output-columns=80 --ssh --coverage-xml=/tmp/coverage.xml --xml=/tmp/xml-unittests-output'
|
||||
<% else %>
|
||||
command: '$(kitchen) /tmp/kitchen/testing/tests/runtests.py --run-destructive --output-columns 80 <%= ENV["TESTOPTS"] %>'
|
||||
<% end %>
|
23
Gemfile
Normal file
23
Gemfile
Normal file
@ -0,0 +1,23 @@
|
||||
# This file is only used for running the test suite with kitchen-salt.
|
||||
|
||||
source "https://rubygems.org"
|
||||
|
||||
gem "test-kitchen"
|
||||
gem "kitchen-salt", :git => 'https://github.com/gtmanfred/kitchen-salt.git'
|
||||
gem 'git'
|
||||
|
||||
group :docker do
|
||||
gem 'kitchen-docker', :git => 'https://github.com/test-kitchen/kitchen-docker.git'
|
||||
end
|
||||
|
||||
group :opennebula do
|
||||
gem 'kitchen-opennebula', :git => 'https://github.com/gtmanfred/kitchen-opennebula.git'
|
||||
gem 'xmlrpc'
|
||||
end
|
||||
|
||||
group :windows do
|
||||
gem 'vagrant-wrapper'
|
||||
gem 'kitchen-vagrant'
|
||||
gem 'winrm', '~>2.0'
|
||||
gem 'winrm-fs', '~>1.0'
|
||||
end
|
@ -95,19 +95,19 @@ globally available or passed in through function arguments, file data, etc.
|
||||
Mocking Loader Modules
|
||||
----------------------
|
||||
|
||||
Salt loader modules use a series of globally available dunder variables,
|
||||
``__salt__``, ``__opts__``, ``__pillar__``, etc. To facilitate testing these
|
||||
modules a mixin class was created, ``LoaderModuleMockMixin`` which can be found
|
||||
in ``tests/support/mixins.py``. The reason for the exitance of this class is
|
||||
because, historycally, and because it was easier, one would add these dunder
|
||||
variables directly on the imported module. This however, introduces unexpected
|
||||
behavior when running the full test suite since those attributes would not be
|
||||
removed once we were done testing the module and would therefor leak to other
|
||||
modules being tested with unpredictable results. This is the kind of work that
|
||||
should be defered to mock, and that's exactly what this mixin class does.
|
||||
Salt loader modules use a series of globally available dunder variables,
|
||||
``__salt__``, ``__opts__``, ``__pillar__``, etc. To facilitate testing these
|
||||
modules a mixin class was created, ``LoaderModuleMockMixin`` which can be found
|
||||
in ``tests/support/mixins.py``. The reason for the existance of this class is
|
||||
because historiclly and because it was easier, one would add these dunder
|
||||
variables directly on the imported module. This however, introduces unexpected
|
||||
behavior when running the full test suite since those attributes would not be
|
||||
removed once we were done testing the module and would therefore leak to other
|
||||
modules being tested with unpredictable results. This is the kind of work that
|
||||
should be deferred to mock, and that's exactly what this mixin class does.
|
||||
|
||||
As an example, if one needs to specify some options which should be available
|
||||
to the module being tests one should do:
|
||||
As an example, if one needs to specify some options which should be available
|
||||
to the module being tested one should do:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@ -122,7 +122,7 @@ to the module being tests one should do:
|
||||
}
|
||||
}
|
||||
|
||||
Consider this more extensive example from
|
||||
Consider this more extensive example from
|
||||
``tests/unit/modules/test_libcloud_dns.py``:
|
||||
|
||||
.. code-block:: python
|
||||
@ -173,10 +173,10 @@ Consider this more extensive example from
|
||||
return {libcloud_dns: module_globals}
|
||||
|
||||
|
||||
What happens on the above example is that, we mock a call to
|
||||
`__salt__['config.option']` to return the configuration needed for the
|
||||
execution of the tests. Additionally, if the ``libcloud`` library is not
|
||||
available, since that's not actually part of whats being tested, we mocked that
|
||||
What happens in the above example is we mock a call to
|
||||
`__salt__['config.option']` to return the configuration needed for the
|
||||
execution of the tests. Additionally, if the ``libcloud`` library is not
|
||||
available, since that's not actually part of what's being tested, we mocked that
|
||||
import by patching ``sys.modules`` when tests are running.
|
||||
|
||||
|
||||
@ -245,7 +245,7 @@ To understand how one might integrate Mock into writing a unit test for Salt,
|
||||
let's imagine a scenario in which we're testing an execution module that's
|
||||
designed to operate on a database. Furthermore, let's imagine two separate
|
||||
methods, here presented in pseduo-code in an imaginary execution module called
|
||||
'db.py.
|
||||
'db.py'.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
@ -9,7 +9,7 @@ Module to provide redis functionality to Salt
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
redis.host: 'localhost'
|
||||
redis.host: 'salt'
|
||||
redis.port: 6379
|
||||
redis.db: 0
|
||||
redis.password: None
|
||||
|
@ -36,6 +36,60 @@ def __virtual__():
|
||||
return (False, "Module win_groupadd: module only works on Windows systems")
|
||||
|
||||
|
||||
def _get_computer_object():
|
||||
'''
|
||||
A helper function to get the object for the local machine
|
||||
|
||||
Returns:
|
||||
object: Returns the computer object for the local machine
|
||||
'''
|
||||
pythoncom.CoInitialize()
|
||||
nt = win32com.client.Dispatch('AdsNameSpaces')
|
||||
return nt.GetObject('', 'WinNT://.,computer')
|
||||
|
||||
|
||||
def _get_group_object(name):
|
||||
'''
|
||||
A helper function to get a specified group object
|
||||
|
||||
Args:
|
||||
|
||||
name (str): The name of the object
|
||||
|
||||
Returns:
|
||||
object: The specified group object
|
||||
'''
|
||||
pythoncom.CoInitialize()
|
||||
nt = win32com.client.Dispatch('AdsNameSpaces')
|
||||
return nt.GetObject('', 'WinNT://./' + name + ',group')
|
||||
|
||||
|
||||
def _get_all_groups():
|
||||
'''
|
||||
A helper function that gets a list of group objects for all groups on the
|
||||
machine
|
||||
|
||||
Returns:
|
||||
iter: A list of objects for all groups on the machine
|
||||
'''
|
||||
pythoncom.CoInitialize()
|
||||
nt = win32com.client.Dispatch('AdsNameSpaces')
|
||||
results = nt.GetObject('', 'WinNT://.')
|
||||
results.Filter = ['group']
|
||||
return results
|
||||
|
||||
|
||||
def _get_username(member):
|
||||
'''
|
||||
Resolve the username from the member object returned from a group query
|
||||
|
||||
Returns:
|
||||
str: The username converted to domain\\username format
|
||||
'''
|
||||
return member.ADSPath.replace('WinNT://', '').replace(
|
||||
'/', '\\').encode('ascii', 'backslashreplace')
|
||||
|
||||
|
||||
def add(name, **kwargs):
|
||||
'''
|
||||
Add the specified group
|
||||
@ -60,10 +114,8 @@ def add(name, **kwargs):
|
||||
'comment': ''}
|
||||
|
||||
if not info(name):
|
||||
pythoncom.CoInitialize()
|
||||
nt = win32com.client.Dispatch('AdsNameSpaces')
|
||||
compObj = _get_computer_object()
|
||||
try:
|
||||
compObj = nt.GetObject('', 'WinNT://.,computer')
|
||||
newGroup = compObj.Create('group', name)
|
||||
newGroup.SetInfo()
|
||||
ret['changes'].append('Successfully created group {0}'.format(name))
|
||||
@ -104,10 +156,8 @@ def delete(name, **kwargs):
|
||||
'comment': ''}
|
||||
|
||||
if info(name):
|
||||
pythoncom.CoInitialize()
|
||||
nt = win32com.client.Dispatch('AdsNameSpaces')
|
||||
compObj = _get_computer_object()
|
||||
try:
|
||||
compObj = nt.GetObject('', 'WinNT://.,computer')
|
||||
compObj.Delete('group', name)
|
||||
ret['changes'].append(('Successfully removed group {0}').format(name))
|
||||
except pywintypes.com_error as com_err:
|
||||
@ -144,17 +194,10 @@ def info(name):
|
||||
|
||||
salt '*' group.info foo
|
||||
'''
|
||||
pythoncom.CoInitialize()
|
||||
nt = win32com.client.Dispatch('AdsNameSpaces')
|
||||
|
||||
try:
|
||||
groupObj = nt.GetObject('', 'WinNT://./' + name + ',group')
|
||||
groupObj = _get_group_object(name)
|
||||
gr_name = groupObj.Name
|
||||
gr_mem = []
|
||||
for member in groupObj.members():
|
||||
gr_mem.append(
|
||||
member.ADSPath.replace('WinNT://', '').replace(
|
||||
'/', '\\').encode('ascii', 'backslashreplace'))
|
||||
gr_mem = [_get_username(x) for x in groupObj.members()]
|
||||
except pywintypes.com_error:
|
||||
return False
|
||||
|
||||
@ -193,20 +236,12 @@ def getent(refresh=False):
|
||||
|
||||
ret = []
|
||||
|
||||
pythoncom.CoInitialize()
|
||||
nt = win32com.client.Dispatch('AdsNameSpaces')
|
||||
results = _get_all_groups()
|
||||
|
||||
results = nt.GetObject('', 'WinNT://.')
|
||||
results.Filter = ['group']
|
||||
for result in results:
|
||||
member_list = []
|
||||
for member in result.members():
|
||||
member_list.append(
|
||||
member.AdsPath.replace('WinNT://', '').replace(
|
||||
'/', '\\').encode('ascii', 'backslashreplace'))
|
||||
group = {'gid': __salt__['file.group_to_gid'](result.name),
|
||||
'members': member_list,
|
||||
'name': result.name,
|
||||
group = {'gid': __salt__['file.group_to_gid'](result.Name),
|
||||
'members': [_get_username(x) for x in result.members()],
|
||||
'name': result.Name,
|
||||
'passwd': 'x'}
|
||||
ret.append(group)
|
||||
__context__['group.getent'] = ret
|
||||
@ -240,17 +275,21 @@ def adduser(name, username, **kwargs):
|
||||
'changes': {'Users Added': []},
|
||||
'comment': ''}
|
||||
|
||||
pythoncom.CoInitialize()
|
||||
nt = win32com.client.Dispatch('AdsNameSpaces')
|
||||
groupObj = nt.GetObject('', 'WinNT://./' + name + ',group')
|
||||
existingMembers = []
|
||||
for member in groupObj.members():
|
||||
existingMembers.append(
|
||||
member.ADSPath.replace('WinNT://', '').replace(
|
||||
'/', '\\').encode('ascii', 'backslashreplace').lower())
|
||||
try:
|
||||
groupObj = _get_group_object(name)
|
||||
except pywintypes.com_error as com_err:
|
||||
if len(com_err.excepinfo) >= 2:
|
||||
friendly_error = com_err.excepinfo[2].rstrip('\r\n')
|
||||
ret['result'] = False
|
||||
ret['comment'] = 'Failure accessing group {0}. {1}' \
|
||||
''.format(name, friendly_error)
|
||||
return ret
|
||||
|
||||
existingMembers = [_get_username(x) for x in groupObj.members()]
|
||||
username = salt.utils.win_functions.get_sam_name(username)
|
||||
|
||||
try:
|
||||
if salt.utils.win_functions.get_sam_name(username).lower() not in existingMembers:
|
||||
if username not in existingMembers:
|
||||
if not __opts__['test']:
|
||||
groupObj.Add('WinNT://' + username.replace('\\', '/'))
|
||||
|
||||
@ -299,17 +338,20 @@ def deluser(name, username, **kwargs):
|
||||
'changes': {'Users Removed': []},
|
||||
'comment': ''}
|
||||
|
||||
pythoncom.CoInitialize()
|
||||
nt = win32com.client.Dispatch('AdsNameSpaces')
|
||||
groupObj = nt.GetObject('', 'WinNT://./' + name + ',group')
|
||||
existingMembers = []
|
||||
for member in groupObj.members():
|
||||
existingMembers.append(
|
||||
member.ADSPath.replace('WinNT://', '').replace(
|
||||
'/', '\\').encode('ascii', 'backslashreplace').lower())
|
||||
try:
|
||||
groupObj = _get_group_object(name)
|
||||
except pywintypes.com_error as com_err:
|
||||
if len(com_err.excepinfo) >= 2:
|
||||
friendly_error = com_err.excepinfo[2].rstrip('\r\n')
|
||||
ret['result'] = False
|
||||
ret['comment'] = 'Failure accessing group {0}. {1}' \
|
||||
''.format(name, friendly_error)
|
||||
return ret
|
||||
|
||||
existingMembers = [_get_username(x) for x in groupObj.members()]
|
||||
|
||||
try:
|
||||
if salt.utils.win_functions.get_sam_name(username).lower() in existingMembers:
|
||||
if salt.utils.win_functions.get_sam_name(username) in existingMembers:
|
||||
if not __opts__['test']:
|
||||
groupObj.Remove('WinNT://' + username.replace('\\', '/'))
|
||||
|
||||
@ -365,10 +407,8 @@ def members(name, members_list, **kwargs):
|
||||
ret['comment'].append('Members is not a list object')
|
||||
return ret
|
||||
|
||||
pythoncom.CoInitialize()
|
||||
nt = win32com.client.Dispatch('AdsNameSpaces')
|
||||
try:
|
||||
groupObj = nt.GetObject('', 'WinNT://./' + name + ',group')
|
||||
groupObj = _get_group_object(name)
|
||||
except pywintypes.com_error as com_err:
|
||||
if len(com_err.excepinfo) >= 2:
|
||||
friendly_error = com_err.excepinfo[2].rstrip('\r\n')
|
||||
@ -377,12 +417,7 @@ def members(name, members_list, **kwargs):
|
||||
'Failure accessing group {0}. {1}'
|
||||
).format(name, friendly_error))
|
||||
return ret
|
||||
existingMembers = []
|
||||
for member in groupObj.members():
|
||||
existingMembers.append(
|
||||
member.ADSPath.replace('WinNT://', '').replace(
|
||||
'/', '\\').encode('ascii', 'backslashreplace').lower())
|
||||
|
||||
existingMembers = [_get_username(x) for x in groupObj.members()]
|
||||
existingMembers.sort()
|
||||
members_list.sort()
|
||||
|
||||
@ -448,18 +483,14 @@ def list_groups(refresh=False):
|
||||
salt '*' group.list_groups
|
||||
'''
|
||||
if 'group.list_groups' in __context__ and not refresh:
|
||||
return __context__['group.getent']
|
||||
return __context__['group.list_groups']
|
||||
|
||||
results = _get_all_groups()
|
||||
|
||||
ret = []
|
||||
|
||||
pythoncom.CoInitialize()
|
||||
nt = win32com.client.Dispatch('AdsNameSpaces')
|
||||
|
||||
results = nt.GetObject('', 'WinNT://.')
|
||||
results.Filter = ['group']
|
||||
|
||||
for result in results:
|
||||
ret.append(result.name)
|
||||
ret.append(result.Name)
|
||||
|
||||
__context__['group.list_groups'] = ret
|
||||
|
||||
|
@ -40,6 +40,7 @@ Current known limitations
|
||||
|
||||
# Import python libs
|
||||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
import io
|
||||
import os
|
||||
import logging
|
||||
@ -4082,7 +4083,7 @@ def _write_regpol_data(data_to_write,
|
||||
gpt_ini_data = ''
|
||||
if os.path.exists(gpt_ini_path):
|
||||
with salt.utils.fopen(gpt_ini_path, 'rb') as gpt_file:
|
||||
gpt_ini_data = gpt_file.read()
|
||||
gpt_ini_data = salt.utils.to_str(gpt_file.read())
|
||||
if not _regexSearchRegPolData(r'\[General\]\r\n', gpt_ini_data):
|
||||
gpt_ini_data = '[General]\r\n' + gpt_ini_data
|
||||
if _regexSearchRegPolData(r'{0}='.format(re.escape(gpt_extension)), gpt_ini_data):
|
||||
@ -4137,7 +4138,7 @@ def _write_regpol_data(data_to_write,
|
||||
gpt_ini_data[general_location.end():])
|
||||
if gpt_ini_data:
|
||||
with salt.utils.fopen(gpt_ini_path, 'wb') as gpt_file:
|
||||
gpt_file.write(gpt_ini_data)
|
||||
gpt_file.write(salt.utils.to_bytes(gpt_ini_data))
|
||||
except Exception as e:
|
||||
msg = 'An error occurred attempting to write to {0}, the exception was {1}'.format(
|
||||
gpt_ini_path, e)
|
||||
@ -5375,7 +5376,7 @@ def set_(computer_policy=None, user_policy=None,
|
||||
_regedits[regedit]['policy']['Registry']['Type'])
|
||||
else:
|
||||
_ret = __salt__['reg.delete_value'](
|
||||
_regedits[regedit]['polic']['Registry']['Hive'],
|
||||
_regedits[regedit]['policy']['Registry']['Hive'],
|
||||
_regedits[regedit]['policy']['Registry']['Path'],
|
||||
_regedits[regedit]['policy']['Registry']['Value'])
|
||||
if not _ret:
|
||||
|
@ -2855,6 +2855,7 @@ def directory(name,
|
||||
if __opts__['test']:
|
||||
ret['result'] = presult
|
||||
ret['comment'] = pcomment
|
||||
ret['changes'] = ret['pchanges']
|
||||
return ret
|
||||
|
||||
if not os.path.isdir(name):
|
||||
|
@ -1330,10 +1330,14 @@ def fopen(*args, **kwargs):
|
||||
if len(args) > 1:
|
||||
args = list(args)
|
||||
if 'b' not in args[1]:
|
||||
args[1] += 'b'
|
||||
elif kwargs.get('mode', None):
|
||||
args[1] = args[1].replace('t', 'b')
|
||||
if 'b' not in args[1]:
|
||||
args[1] += 'b'
|
||||
elif kwargs.get('mode'):
|
||||
if 'b' not in kwargs['mode']:
|
||||
kwargs['mode'] += 'b'
|
||||
kwargs['mode'] = kwargs['mode'].replace('t', 'b')
|
||||
if 'b' not in kwargs['mode']:
|
||||
kwargs['mode'] += 'b'
|
||||
else:
|
||||
# the default is to read
|
||||
kwargs['mode'] = 'rb'
|
||||
|
@ -439,7 +439,7 @@ class GitProvider(object):
|
||||
return root_dir
|
||||
log.error(
|
||||
'Root path \'%s\' not present in %s remote \'%s\', '
|
||||
'skipping.', self.root, self.role, self.id
|
||||
'skipping.', self.root(), self.role, self.id
|
||||
)
|
||||
return None
|
||||
|
||||
|
@ -800,7 +800,10 @@ class TestDaemon(object):
|
||||
|
||||
# Set up config options that require internal data
|
||||
master_opts['pillar_roots'] = syndic_master_opts['pillar_roots'] = {
|
||||
'base': [os.path.join(FILES, 'pillar', 'base')]
|
||||
'base': [
|
||||
RUNTIME_VARS.TMP_PILLAR_TREE,
|
||||
os.path.join(FILES, 'pillar', 'base'),
|
||||
]
|
||||
}
|
||||
master_opts['file_roots'] = syndic_master_opts['file_roots'] = {
|
||||
'base': [
|
||||
@ -976,6 +979,7 @@ class TestDaemon(object):
|
||||
sub_minion_opts['sock_dir'],
|
||||
minion_opts['sock_dir'],
|
||||
RUNTIME_VARS.TMP_STATE_TREE,
|
||||
RUNTIME_VARS.TMP_PILLAR_TREE,
|
||||
RUNTIME_VARS.TMP_PRODENV_STATE_TREE,
|
||||
TMP,
|
||||
],
|
||||
@ -1087,7 +1091,8 @@ class TestDaemon(object):
|
||||
os.chmod(path, stat.S_IRWXU)
|
||||
func(path)
|
||||
|
||||
for dirname in (TMP, RUNTIME_VARS.TMP_STATE_TREE, RUNTIME_VARS.TMP_PRODENV_STATE_TREE):
|
||||
for dirname in (TMP, RUNTIME_VARS.TMP_STATE_TREE,
|
||||
RUNTIME_VARS.TMP_PILLAR_TREE, RUNTIME_VARS.TMP_PRODENV_STATE_TREE):
|
||||
if os.path.isdir(dirname):
|
||||
shutil.rmtree(dirname, onerror=remove_readonly)
|
||||
|
||||
|
@ -5,10 +5,16 @@ Integration tests for the saltutil module.
|
||||
|
||||
# Import Python libs
|
||||
from __future__ import absolute_import
|
||||
import os
|
||||
import time
|
||||
import textwrap
|
||||
|
||||
# Import Salt Testing libs
|
||||
from tests.support.case import ModuleCase
|
||||
from tests.support.paths import TMP_PILLAR_TREE
|
||||
|
||||
# Import Salt Libs
|
||||
import salt.utils
|
||||
|
||||
|
||||
class SaltUtilModuleTest(ModuleCase):
|
||||
@ -153,3 +159,38 @@ class SaltUtilSyncModuleTest(ModuleCase):
|
||||
ret = self.run_function('saltutil.sync_all', extmod_whitelist={'modules': ['runtests_decorators']},
|
||||
extmod_blacklist={'modules': ['runtests_decorators']})
|
||||
self.assertEqual(ret, expected_return)
|
||||
|
||||
|
||||
class SaltUtilSyncPillarTest(ModuleCase):
|
||||
'''
|
||||
Testcase for the saltutil sync pillar module
|
||||
'''
|
||||
|
||||
def test_pillar_refresh(self):
|
||||
'''
|
||||
test pillar refresh module
|
||||
'''
|
||||
pillar_key = 'itworked'
|
||||
|
||||
pre_pillar = self.run_function('pillar.raw')
|
||||
self.assertNotIn(pillar_key, pre_pillar.get(pillar_key, 'didnotwork'))
|
||||
|
||||
with salt.utils.fopen(os.path.join(TMP_PILLAR_TREE, 'add_pillar.sls'), 'w') as fp:
|
||||
fp.write('{0}: itworked'.format(pillar_key))
|
||||
|
||||
with salt.utils.fopen(os.path.join(TMP_PILLAR_TREE, 'top.sls'), 'w') as fp:
|
||||
fp.write(textwrap.dedent('''\
|
||||
base:
|
||||
'*':
|
||||
- add_pillar
|
||||
'''))
|
||||
|
||||
pillar_refresh = self.run_function('saltutil.refresh_pillar')
|
||||
wait = self.run_function('test.sleep', [1])
|
||||
|
||||
post_pillar = self.run_function('pillar.raw')
|
||||
self.assertIn(pillar_key, post_pillar.get(pillar_key, 'didnotwork'))
|
||||
|
||||
def tearDown(self):
|
||||
for filename in os.listdir(TMP_PILLAR_TREE):
|
||||
os.remove(os.path.join(TMP_PILLAR_TREE, filename))
|
||||
|
@ -67,3 +67,23 @@ class ProxyMinionSimpleTestCase(ModuleCase):
|
||||
ret = self.run_function('service.start', ['samba'], minion_tgt='proxytest')
|
||||
ret = self.run_function('service.status', ['samba'], minion_tgt='proxytest')
|
||||
self.assertTrue(ret)
|
||||
|
||||
def test_service_get_all(self):
|
||||
ret = self.run_function('service.get_all', minion_tgt='proxytest')
|
||||
self.assertTrue(ret)
|
||||
self.assertIn('samba', ' '.join(ret))
|
||||
|
||||
def test_grains_items(self):
|
||||
ret = self.run_function('grains.items', minion_tgt='proxytest')
|
||||
self.assertEqual(ret['kernel'], 'proxy')
|
||||
self.assertEqual(ret['kernelrelease'], 'proxy')
|
||||
|
||||
def test_state_apply(self):
|
||||
ret = self.run_function('state.apply', ['core'], minion_tgt='proxytest')
|
||||
for key, value in ret.items():
|
||||
self.assertTrue(value['result'])
|
||||
|
||||
def test_state_highstate(self):
|
||||
ret = self.run_function('state.highstate', minion_tgt='proxytest')
|
||||
for key, value in ret.items():
|
||||
self.assertTrue(value['result'])
|
||||
|
@ -6,49 +6,24 @@ Tests for the spm build utility
|
||||
from __future__ import absolute_import
|
||||
import os
|
||||
import shutil
|
||||
import textwrap
|
||||
|
||||
# Import Salt libs
|
||||
import salt.utils
|
||||
|
||||
# Import Salt Testing libs
|
||||
from tests.support.case import SPMCase
|
||||
from tests.support.case import SPMCase, ModuleCase
|
||||
from tests.support.helpers import destructiveTest
|
||||
|
||||
# Import Salt Libraries
|
||||
import salt.utils
|
||||
from tests.support.unit import skipIf
|
||||
|
||||
|
||||
@destructiveTest
|
||||
class SPMBuildTest(SPMCase):
|
||||
class SPMBuildTest(SPMCase, ModuleCase):
|
||||
'''
|
||||
Validate the spm build command
|
||||
'''
|
||||
def setUp(self):
|
||||
self.config = self._spm_config()
|
||||
self.formula_dir = os.path.join(' '.join(self.config['file_roots']['base']), 'formulas')
|
||||
self.formula_sls_dir = os.path.join(self.formula_dir, 'apache')
|
||||
self.formula_sls = os.path.join(self.formula_sls_dir, 'apache.sls')
|
||||
self.formula_file = os.path.join(self.formula_dir, 'FORMULA')
|
||||
|
||||
dirs = [self.formula_dir, self.formula_sls_dir]
|
||||
for formula_dir in dirs:
|
||||
os.makedirs(formula_dir)
|
||||
|
||||
with salt.utils.fopen(self.formula_sls, 'w') as fp:
|
||||
fp.write(textwrap.dedent('''\
|
||||
install-apache:
|
||||
pkg.installed:
|
||||
- name: apache2
|
||||
'''))
|
||||
|
||||
with salt.utils.fopen(self.formula_file, 'w') as fp:
|
||||
fp.write(textwrap.dedent('''\
|
||||
name: apache
|
||||
os: RedHat, Debian, Ubuntu, Suse, FreeBSD
|
||||
os_family: RedHat, Debian, Suse, FreeBSD
|
||||
version: 201506
|
||||
release: 2
|
||||
summary: Formula for installing Apache
|
||||
description: Formula for installing Apache
|
||||
'''))
|
||||
self._spm_build_files(self.config)
|
||||
|
||||
def test_spm_build(self):
|
||||
'''
|
||||
@ -61,5 +36,44 @@ class SPMBuildTest(SPMCase):
|
||||
# Make sure formula path dir is created
|
||||
self.assertTrue(os.path.isdir(self.config['formula_path']))
|
||||
|
||||
@skipIf(salt.utils.which('fallocate') is None, 'fallocate not installed')
|
||||
def test_spm_build_big_file(self):
|
||||
'''
|
||||
test spm build
|
||||
'''
|
||||
big_file = self.run_function('cmd.run',
|
||||
['fallocate -l 1G {0}'.format(os.path.join(self.formula_sls_dir,
|
||||
'bigfile.txt'))])
|
||||
build_spm = self.run_spm('build', self.config, self.formula_dir)
|
||||
spm_file = os.path.join(self.config['spm_build_dir'], 'apache-201506-2.spm')
|
||||
install = self.run_spm('install', self.config, spm_file)
|
||||
|
||||
get_files = self.run_spm('files', self.config, 'apache')
|
||||
|
||||
files = ['apache.sls', 'bigfile.txt']
|
||||
for sls in files:
|
||||
self.assertIn(sls, ' '.join(get_files))
|
||||
|
||||
def test_spm_build_exclude(self):
|
||||
'''
|
||||
test spm build
|
||||
'''
|
||||
git_dir = os.path.join(self.formula_sls_dir, '.git')
|
||||
os.makedirs(git_dir)
|
||||
files = ['donotbuild1', 'donotbuild2', 'donotbuild3']
|
||||
|
||||
for git_file in files:
|
||||
with salt.utils.fopen(os.path.join(git_dir, git_file), 'w') as fp:
|
||||
fp.write('Please do not include me in build')
|
||||
|
||||
build_spm = self.run_spm('build', self.config, self.formula_dir)
|
||||
spm_file = os.path.join(self.config['spm_build_dir'], 'apache-201506-2.spm')
|
||||
install = self.run_spm('install', self.config, spm_file)
|
||||
|
||||
get_files = self.run_spm('files', self.config, 'apache')
|
||||
|
||||
for git_file in files:
|
||||
self.assertNotIn(git_file, ' '.join(get_files))
|
||||
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self._tmp_spm)
|
||||
|
36
tests/integration/spm/test_files.py
Normal file
36
tests/integration/spm/test_files.py
Normal file
@ -0,0 +1,36 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Tests for the spm files utility
|
||||
'''
|
||||
# Import python libs
|
||||
from __future__ import absolute_import
|
||||
import os
|
||||
import shutil
|
||||
|
||||
# Import Salt Testing libs
|
||||
from tests.support.case import SPMCase
|
||||
from tests.support.helpers import destructiveTest
|
||||
|
||||
|
||||
@destructiveTest
|
||||
class SPMFilesTest(SPMCase):
|
||||
'''
|
||||
Validate the spm files command
|
||||
'''
|
||||
def setUp(self):
|
||||
self.config = self._spm_config()
|
||||
self._spm_build_files(self.config)
|
||||
|
||||
def test_spm_files(self):
|
||||
'''
|
||||
test spm files
|
||||
'''
|
||||
self._spm_create_update_repo(self.config)
|
||||
install = self.run_spm('install', self.config, 'apache')
|
||||
get_files = self.run_spm('files', self.config, 'apache')
|
||||
|
||||
os.path.exists(os.path.join(self.config['formula_path'], 'apache',
|
||||
'apache.sls'))
|
||||
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self._tmp_spm)
|
36
tests/integration/spm/test_info.py
Normal file
36
tests/integration/spm/test_info.py
Normal file
@ -0,0 +1,36 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Tests for the spm info utility
|
||||
'''
|
||||
# Import python libs
|
||||
from __future__ import absolute_import
|
||||
import shutil
|
||||
|
||||
# Import Salt Testing libs
|
||||
from tests.support.case import SPMCase
|
||||
from tests.support.helpers import destructiveTest
|
||||
|
||||
|
||||
@destructiveTest
|
||||
class SPMInfoTest(SPMCase):
|
||||
'''
|
||||
Validate the spm info command
|
||||
'''
|
||||
def setUp(self):
|
||||
self.config = self._spm_config()
|
||||
self._spm_build_files(self.config)
|
||||
|
||||
def test_spm_info(self):
|
||||
'''
|
||||
test spm build
|
||||
'''
|
||||
self._spm_create_update_repo(self.config)
|
||||
install = self.run_spm('install', self.config, 'apache')
|
||||
get_info = self.run_spm('info', self.config, 'apache')
|
||||
|
||||
check_info = ['Supported OSes', 'Supported OS', 'installing Apache']
|
||||
for info in check_info:
|
||||
self.assertIn(info, ''.join(get_info))
|
||||
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self._tmp_spm)
|
50
tests/integration/spm/test_install.py
Normal file
50
tests/integration/spm/test_install.py
Normal file
@ -0,0 +1,50 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Tests for the spm install utility
|
||||
'''
|
||||
# Import python libs
|
||||
from __future__ import absolute_import
|
||||
import os
|
||||
import shutil
|
||||
|
||||
# Import Salt Testing libs
|
||||
from tests.support.case import SPMCase
|
||||
from tests.support.helpers import destructiveTest
|
||||
|
||||
|
||||
@destructiveTest
|
||||
class SPMInstallTest(SPMCase):
|
||||
'''
|
||||
Validate the spm install command
|
||||
'''
|
||||
def setUp(self):
|
||||
self.config = self._spm_config()
|
||||
self._spm_build_files(self.config)
|
||||
|
||||
def test_spm_install_local_dir(self):
|
||||
'''
|
||||
test spm install from local directory
|
||||
'''
|
||||
build_spm = self.run_spm('build', self.config, self.formula_dir)
|
||||
spm_file = os.path.join(self.config['spm_build_dir'],
|
||||
'apache-201506-2.spm')
|
||||
|
||||
install = self.run_spm('install', self.config, spm_file)
|
||||
|
||||
sls = os.path.join(self.config['formula_path'], 'apache', 'apache.sls')
|
||||
|
||||
self.assertTrue(os.path.exists(sls))
|
||||
|
||||
def test_spm_install_from_repo(self):
|
||||
'''
|
||||
test spm install from repo
|
||||
'''
|
||||
self._spm_create_update_repo(self.config)
|
||||
install = self.run_spm('install', self.config, 'apache')
|
||||
|
||||
sls = os.path.join(self.config['formula_path'], 'apache', 'apache.sls')
|
||||
|
||||
self.assertTrue(os.path.exists(sls))
|
||||
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self._tmp_spm)
|
45
tests/integration/spm/test_remove.py
Normal file
45
tests/integration/spm/test_remove.py
Normal file
@ -0,0 +1,45 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Tests for the spm remove utility
|
||||
'''
|
||||
# Import python libs
|
||||
from __future__ import absolute_import
|
||||
import os
|
||||
import shutil
|
||||
|
||||
# Import Salt Testing libs
|
||||
from tests.support.case import SPMCase
|
||||
from tests.support.helpers import destructiveTest
|
||||
|
||||
|
||||
@destructiveTest
|
||||
class SPMRemoveTest(SPMCase):
|
||||
'''
|
||||
Validate the spm remove command
|
||||
'''
|
||||
def setUp(self):
|
||||
self.config = self._spm_config()
|
||||
self._spm_build_files(self.config)
|
||||
|
||||
def test_spm_remove(self):
|
||||
'''
|
||||
test spm remove from an inital repo install
|
||||
'''
|
||||
# first install apache package
|
||||
self._spm_create_update_repo(self.config)
|
||||
install = self.run_spm('install', self.config, 'apache')
|
||||
|
||||
sls = os.path.join(self.config['formula_path'], 'apache', 'apache.sls')
|
||||
|
||||
self.assertTrue(os.path.exists(sls))
|
||||
|
||||
#now remove an make sure file is removed
|
||||
remove = self.run_spm('remove', self.config, 'apache')
|
||||
sls = os.path.join(self.config['formula_path'], 'apache', 'apache.sls')
|
||||
|
||||
self.assertFalse(os.path.exists(sls))
|
||||
|
||||
self.assertIn('... removing apache', remove)
|
||||
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self._tmp_spm)
|
36
tests/integration/spm/test_repo.py
Normal file
36
tests/integration/spm/test_repo.py
Normal file
@ -0,0 +1,36 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Tests for the spm repo
|
||||
'''
|
||||
# Import python libs
|
||||
from __future__ import absolute_import
|
||||
import os
|
||||
import shutil
|
||||
|
||||
# Import Salt Testing libs
|
||||
from tests.support.case import SPMCase
|
||||
from tests.support.helpers import destructiveTest
|
||||
|
||||
|
||||
@destructiveTest
|
||||
class SPMRepoTest(SPMCase):
|
||||
'''
|
||||
Validate commands related to spm repo
|
||||
'''
|
||||
def setUp(self):
|
||||
self.config = self._spm_config()
|
||||
self._spm_build_files(self.config)
|
||||
|
||||
def test_spm_create_update_repo(self):
|
||||
'''
|
||||
test spm create_repo
|
||||
'''
|
||||
self._spm_create_update_repo(self.config)
|
||||
|
||||
self.assertTrue(os.path.exists(self.config['spm_db']))
|
||||
|
||||
l_repo_file = os.path.join(self.config['spm_cache_dir'], 'local_repo.p')
|
||||
self.assertTrue(os.path.exists(l_repo_file))
|
||||
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self._tmp_spm)
|
@ -130,6 +130,9 @@ TEST_SUITES = {
|
||||
'returners':
|
||||
{'display_name': 'Returners',
|
||||
'path': 'integration/returners'},
|
||||
'spm':
|
||||
{'display_name': 'SPM',
|
||||
'path': 'integration/spm'},
|
||||
'loader':
|
||||
{'display_name': 'Loader',
|
||||
'path': 'integration/loader'},
|
||||
@ -338,6 +341,13 @@ class SaltTestsuiteParser(SaltCoverageTestingParser):
|
||||
action='store_true',
|
||||
help='Run salt/returners/*.py tests'
|
||||
)
|
||||
self.test_selection_group.add_option(
|
||||
'--spm',
|
||||
dest='spm',
|
||||
default=False,
|
||||
action='store_true',
|
||||
help='Run spm integration tests'
|
||||
)
|
||||
self.test_selection_group.add_option(
|
||||
'-l',
|
||||
'--loader',
|
||||
|
@ -22,6 +22,7 @@ import time
|
||||
import stat
|
||||
import errno
|
||||
import signal
|
||||
import textwrap
|
||||
import logging
|
||||
import tempfile
|
||||
import subprocess
|
||||
@ -564,11 +565,60 @@ class ShellCase(ShellTestCase, AdaptedConfigurationTestCaseMixin, ScriptPathMixi
|
||||
timeout=timeout)
|
||||
|
||||
|
||||
class SPMTestUserInterface(object):
|
||||
'''
|
||||
Test user interface to SPMClient
|
||||
'''
|
||||
def __init__(self):
|
||||
self._status = []
|
||||
self._confirm = []
|
||||
self._error = []
|
||||
|
||||
def status(self, msg):
|
||||
self._status.append(msg)
|
||||
|
||||
def confirm(self, action):
|
||||
self._confirm.append(action)
|
||||
|
||||
def error(self, msg):
|
||||
self._error.append(msg)
|
||||
|
||||
|
||||
class SPMCase(TestCase, AdaptedConfigurationTestCaseMixin):
|
||||
'''
|
||||
Class for handling spm commands
|
||||
'''
|
||||
|
||||
def _spm_build_files(self, config):
|
||||
self.formula_dir = os.path.join(' '.join(config['file_roots']['base']), 'formulas')
|
||||
self.formula_sls_dir = os.path.join(self.formula_dir, 'apache')
|
||||
self.formula_sls = os.path.join(self.formula_sls_dir, 'apache.sls')
|
||||
self.formula_file = os.path.join(self.formula_dir, 'FORMULA')
|
||||
|
||||
dirs = [self.formula_dir, self.formula_sls_dir]
|
||||
for f_dir in dirs:
|
||||
os.makedirs(f_dir)
|
||||
|
||||
import salt.utils
|
||||
|
||||
with salt.utils.fopen(self.formula_sls, 'w') as fp:
|
||||
fp.write(textwrap.dedent('''\
|
||||
install-apache:
|
||||
pkg.installed:
|
||||
- name: apache2
|
||||
'''))
|
||||
|
||||
with salt.utils.fopen(self.formula_file, 'w') as fp:
|
||||
fp.write(textwrap.dedent('''\
|
||||
name: apache
|
||||
os: RedHat, Debian, Ubuntu, Suse, FreeBSD
|
||||
os_family: RedHat, Debian, Suse, FreeBSD
|
||||
version: 201506
|
||||
release: 2
|
||||
summary: Formula for installing Apache
|
||||
description: Formula for installing Apache
|
||||
'''))
|
||||
|
||||
def _spm_config(self):
|
||||
self._tmp_spm = tempfile.mkdtemp()
|
||||
config = self.get_temp_config('minion', **{
|
||||
@ -576,7 +626,7 @@ class SPMCase(TestCase, AdaptedConfigurationTestCaseMixin):
|
||||
'spm_repos_config': os.path.join(self._tmp_spm, 'etc', 'spm.repos'),
|
||||
'spm_cache_dir': os.path.join(self._tmp_spm, 'cache'),
|
||||
'spm_build_dir': os.path.join(self._tmp_spm, 'build'),
|
||||
'spm_build_exclude': ['.git'],
|
||||
'spm_build_exclude': ['apache/.git'],
|
||||
'spm_db_provider': 'sqlite3',
|
||||
'spm_files_provider': 'local',
|
||||
'spm_db': os.path.join(self._tmp_spm, 'packages.db'),
|
||||
@ -595,16 +645,36 @@ class SPMCase(TestCase, AdaptedConfigurationTestCaseMixin):
|
||||
})
|
||||
return config
|
||||
|
||||
def _spm_create_update_repo(self, config):
|
||||
|
||||
build_spm = self.run_spm('build', self.config, self.formula_dir)
|
||||
|
||||
c_repo = self.run_spm('create_repo', self.config,
|
||||
self.config['spm_build_dir'])
|
||||
|
||||
repo_conf_dir = self.config['spm_repos_config'] + '.d'
|
||||
os.makedirs(repo_conf_dir)
|
||||
|
||||
import salt.utils
|
||||
|
||||
with salt.utils.fopen(os.path.join(repo_conf_dir, 'spm.repo'), 'w') as fp:
|
||||
fp.write(textwrap.dedent('''\
|
||||
local_repo:
|
||||
url: file://{0}
|
||||
'''.format(self.config['spm_build_dir'])))
|
||||
|
||||
u_repo = self.run_spm('update_repo', self.config)
|
||||
|
||||
def _spm_client(self, config):
|
||||
import salt.spm
|
||||
ui = salt.spm.SPMCmdlineInterface()
|
||||
client = salt.spm.SPMClient(ui, config)
|
||||
self.ui = SPMTestUserInterface()
|
||||
client = salt.spm.SPMClient(self.ui, config)
|
||||
return client
|
||||
|
||||
def run_spm(self, cmd, config, arg=()):
|
||||
def run_spm(self, cmd, config, arg=None):
|
||||
client = self._spm_client(config)
|
||||
spm_cmd = client.run([cmd, arg])
|
||||
return spm_cmd
|
||||
return self.ui._status
|
||||
|
||||
|
||||
class ModuleCase(TestCase, SaltClientTestCaseMixin):
|
||||
|
68
tests/support/copyartifacts.py
Normal file
68
tests/support/copyartifacts.py
Normal file
@ -0,0 +1,68 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Script for copying back xml junit files from tests
|
||||
'''
|
||||
from __future__ import absolute_import, print_function
|
||||
import argparse # pylint: disable=minimum-python-version
|
||||
import os
|
||||
import paramiko
|
||||
import subprocess
|
||||
import yaml
|
||||
|
||||
|
||||
class DownloadArtifacts(object):
|
||||
def __init__(self, instance, artifacts):
|
||||
self.instance = instance
|
||||
self.artifacts = artifacts
|
||||
self.client = self.setup_transport()
|
||||
|
||||
def setup_transport(self):
|
||||
# pylint: disable=minimum-python-version
|
||||
config = yaml.load(subprocess.check_output(['bundle', 'exec', 'kitchen', 'diagnose', self.instance]))
|
||||
# pylint: enable=minimum-python-version
|
||||
state = config['instances'][self.instance]['state_file']
|
||||
tport = config['instances'][self.instance]['transport']
|
||||
transport = paramiko.Transport((
|
||||
state['hostname'],
|
||||
state.get('port', tport.get('port', 22))
|
||||
))
|
||||
pkey = paramiko.rsakey.RSAKey(
|
||||
filename=state.get('ssh_key', tport.get('ssh_key', '~/.ssh/id_rsa'))
|
||||
)
|
||||
transport.connect(
|
||||
username=state.get('username', tport.get('username', 'root')),
|
||||
pkey=pkey
|
||||
)
|
||||
return paramiko.SFTPClient.from_transport(transport)
|
||||
|
||||
def download(self):
|
||||
for remote, local in self.artifacts:
|
||||
if remote.endswith('/'):
|
||||
for fxml in self.client.listdir(remote):
|
||||
self._do_download(os.path.join(remote, fxml), os.path.join(local, os.path.basename(fxml)))
|
||||
else:
|
||||
self._do_download(remote, os.path.join(local, os.path.basename(remote)))
|
||||
|
||||
def _do_download(self, remote, local):
|
||||
print('Copying from {0} to {1}'.format(remote, local))
|
||||
self.client.get(remote, local)
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description='Jenkins Artifact Download Helper')
|
||||
parser.add_argument(
|
||||
'--instance',
|
||||
required=True,
|
||||
action='store',
|
||||
help='Instance on Test Kitchen to pull from',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--download-artifacts',
|
||||
dest='artifacts',
|
||||
nargs=2,
|
||||
action='append',
|
||||
metavar=('REMOTE_PATH', 'LOCAL_PATH'),
|
||||
help='Download remote artifacts',
|
||||
)
|
||||
args = parser.parse_args()
|
||||
downloader = DownloadArtifacts(args.instance, args.artifacts)
|
||||
downloader.download()
|
@ -52,6 +52,7 @@ PYEXEC = 'python{0}.{1}'.format(*sys.version_info)
|
||||
MOCKBIN = os.path.join(INTEGRATION_TEST_DIR, 'mockbin')
|
||||
SCRIPT_DIR = os.path.join(CODE_DIR, 'scripts')
|
||||
TMP_STATE_TREE = os.path.join(SYS_TMP_DIR, 'salt-temp-state-tree')
|
||||
TMP_PILLAR_TREE = os.path.join(SYS_TMP_DIR, 'salt-temp-pillar-tree')
|
||||
TMP_PRODENV_STATE_TREE = os.path.join(SYS_TMP_DIR, 'salt-temp-prodenv-state-tree')
|
||||
TMP_CONF_DIR = os.path.join(TMP, 'config')
|
||||
TMP_SUB_MINION_CONF_DIR = os.path.join(TMP_CONF_DIR, 'sub-minion')
|
||||
|
@ -215,6 +215,7 @@ RUNTIME_VARS = RuntimeVars(
|
||||
TMP_SYNDIC_MINION_CONF_DIR=paths.TMP_SYNDIC_MINION_CONF_DIR,
|
||||
TMP_SCRIPT_DIR=paths.TMP_SCRIPT_DIR,
|
||||
TMP_STATE_TREE=paths.TMP_STATE_TREE,
|
||||
TMP_PILLAR_TREE=paths.TMP_PILLAR_TREE,
|
||||
TMP_PRODENV_STATE_TREE=paths.TMP_PRODENV_STATE_TREE,
|
||||
RUNNING_TESTS_USER=RUNNING_TESTS_USER,
|
||||
RUNTIME_CONFIGS={}
|
||||
|
@ -10,6 +10,8 @@ from __future__ import absolute_import
|
||||
from tests.support.mixins import LoaderModuleMockMixin
|
||||
from tests.support.unit import TestCase, skipIf
|
||||
from tests.support.mock import (
|
||||
MagicMock,
|
||||
Mock,
|
||||
patch,
|
||||
NO_MOCK,
|
||||
NO_MOCK_REASON
|
||||
@ -17,6 +19,7 @@ from tests.support.mock import (
|
||||
|
||||
# Import Salt Libs
|
||||
import salt.modules.win_groupadd as win_groupadd
|
||||
import salt.utils.win_functions
|
||||
|
||||
# Import Other Libs
|
||||
# pylint: disable=unused-import
|
||||
@ -24,12 +27,46 @@ try:
|
||||
import win32com
|
||||
import pythoncom
|
||||
import pywintypes
|
||||
PYWINTYPES_ERROR = pywintypes.com_error(
|
||||
-1234, 'Exception occurred.', (0, None, 'C', None, 0, -4321), None)
|
||||
HAS_WIN_LIBS = True
|
||||
except ImportError:
|
||||
HAS_WIN_LIBS = False
|
||||
# pylint: enable=unused-import
|
||||
|
||||
|
||||
class MockMember(object):
|
||||
def __init__(self, name):
|
||||
self.ADSPath = name
|
||||
|
||||
|
||||
class MockGroupObj(object):
|
||||
def __init__(self, ads_name, ads_users):
|
||||
self._members = [MockMember(x) for x in ads_users]
|
||||
self.Name = ads_name
|
||||
|
||||
def members(self):
|
||||
return self._members
|
||||
|
||||
def Add(self, name):
|
||||
'''
|
||||
This should be a no-op unless we want to test raising an error, in
|
||||
which case this should be overridden in a subclass.
|
||||
'''
|
||||
pass
|
||||
|
||||
def Remove(self, name):
|
||||
'''
|
||||
This should be a no-op unless we want to test raising an error, in
|
||||
which case this should be overridden in a subclass.
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
if not NO_MOCK:
|
||||
sam_mock = MagicMock(side_effect=lambda x: 'HOST\\' + x)
|
||||
|
||||
|
||||
@skipIf(not HAS_WIN_LIBS, 'win_groupadd unit tests can only be run if win32com, pythoncom, and pywintypes are installed')
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
class WinGroupTestCase(TestCase, LoaderModuleMockMixin):
|
||||
@ -41,106 +78,352 @@ class WinGroupTestCase(TestCase, LoaderModuleMockMixin):
|
||||
win_groupadd: {'__opts__': {'test': False}}
|
||||
}
|
||||
|
||||
# 'add' function tests: 1
|
||||
|
||||
def test_add(self):
|
||||
'''
|
||||
Test if it add the specified group
|
||||
Test adding a new group
|
||||
'''
|
||||
self.assertDictEqual(win_groupadd.add('foo'),
|
||||
{'changes': [], 'name': 'foo', 'result': None,
|
||||
'comment': 'The group foo already exists.'})
|
||||
info = MagicMock(return_value=False)
|
||||
with patch.object(win_groupadd, 'info', info),\
|
||||
patch.object(win_groupadd, '_get_computer_object', Mock()):
|
||||
self.assertDictEqual(win_groupadd.add('foo'),
|
||||
{'changes': ['Successfully created group foo'],
|
||||
'name': 'foo',
|
||||
'result': True,
|
||||
'comment': ''})
|
||||
|
||||
# 'delete' function tests: 1
|
||||
def test_add_group_exists(self):
|
||||
'''
|
||||
Test adding a new group if the group already exists
|
||||
'''
|
||||
info = MagicMock(return_value={'name': 'foo',
|
||||
'passwd': None,
|
||||
'gid': None,
|
||||
'members': ['HOST\\spongebob']})
|
||||
with patch.object(win_groupadd, 'info', info),\
|
||||
patch.object(win_groupadd, '_get_computer_object', Mock()):
|
||||
self.assertDictEqual(win_groupadd.add('foo'),
|
||||
{'changes': [], 'name': 'foo', 'result': None,
|
||||
'comment': 'The group foo already exists.'})
|
||||
|
||||
def test_add_error(self):
|
||||
'''
|
||||
Test adding a group and encountering an error
|
||||
'''
|
||||
class CompObj(object):
|
||||
def Create(self, type, name):
|
||||
raise PYWINTYPES_ERROR
|
||||
|
||||
compobj_mock = MagicMock(return_value=CompObj())
|
||||
|
||||
info = MagicMock(return_value=False)
|
||||
with patch.object(win_groupadd, 'info', info),\
|
||||
patch.object(win_groupadd, '_get_computer_object', compobj_mock):
|
||||
self.assertDictEqual(win_groupadd.add('foo'),
|
||||
{'changes': [],
|
||||
'name': 'foo',
|
||||
'result': False,
|
||||
'comment': 'Failed to create group foo. C'})
|
||||
|
||||
def test_delete(self):
|
||||
'''
|
||||
Test if it remove the specified group
|
||||
Test removing a group
|
||||
'''
|
||||
self.assertDictEqual(win_groupadd.delete('foo'),
|
||||
{'changes': [], 'name': 'foo', 'result': None,
|
||||
'comment': 'The group foo does not exists.'})
|
||||
info = MagicMock(return_value={'name': 'foo',
|
||||
'passwd': None,
|
||||
'gid': None,
|
||||
'members': ['HOST\\spongebob']})
|
||||
with patch.object(win_groupadd, 'info', info), \
|
||||
patch.object(win_groupadd, '_get_computer_object', Mock()):
|
||||
self.assertDictEqual(
|
||||
win_groupadd.delete('foo'),
|
||||
{'changes': ['Successfully removed group foo'],
|
||||
'name': 'foo',
|
||||
'result': True,
|
||||
'comment': ''})
|
||||
|
||||
# 'info' function tests: 1
|
||||
def test_delete_no_group(self):
|
||||
'''
|
||||
Test removing a group that doesn't exists
|
||||
'''
|
||||
info = MagicMock(return_value=False)
|
||||
with patch.object(win_groupadd, 'info', info), \
|
||||
patch.object(win_groupadd, '_get_computer_object', Mock()):
|
||||
self.assertDictEqual(win_groupadd.delete('foo'),
|
||||
{'changes': [], 'name': 'foo', 'result': None,
|
||||
'comment': 'The group foo does not exists.'})
|
||||
|
||||
def test_delete_error(self):
|
||||
'''
|
||||
Test removing a group and encountering an error
|
||||
'''
|
||||
class CompObj(object):
|
||||
def Delete(self, type, name):
|
||||
raise PYWINTYPES_ERROR
|
||||
|
||||
compobj_mock = MagicMock(return_value=CompObj())
|
||||
|
||||
info = MagicMock(return_value={'name': 'foo',
|
||||
'passwd': None,
|
||||
'gid': None,
|
||||
'members': ['HOST\\spongebob']})
|
||||
with patch.object(win_groupadd, 'info', info),\
|
||||
patch.object(win_groupadd, '_get_computer_object', compobj_mock):
|
||||
self.assertDictEqual(
|
||||
win_groupadd.delete('foo'),
|
||||
{'changes': [],
|
||||
'name': 'foo',
|
||||
'result': False,
|
||||
'comment': 'Failed to remove group foo. C'})
|
||||
|
||||
def test_info(self):
|
||||
'''
|
||||
Test if it return information about a group.
|
||||
'''
|
||||
with patch(win_groupadd.win32.client, 'flag', None):
|
||||
self.assertDictEqual(win_groupadd.info('dc=salt'),
|
||||
groupobj_mock = MagicMock(return_value=MockGroupObj('salt', ['WinNT://HOST/steve']))
|
||||
with patch.object(win_groupadd, '_get_group_object', groupobj_mock):
|
||||
self.assertDictEqual(win_groupadd.info('salt'),
|
||||
{'gid': None,
|
||||
'members': ['dc=\\user1'],
|
||||
'members': ['HOST\\steve'],
|
||||
'passwd': None,
|
||||
'name': 'WinNT://./dc=salt,group'})
|
||||
|
||||
with patch(win_groupadd.win32.client, 'flag', 1):
|
||||
self.assertFalse(win_groupadd.info('dc=salt'))
|
||||
|
||||
with patch(win_groupadd.win32.client, 'flag', 2):
|
||||
self.assertFalse(win_groupadd.info('dc=salt'))
|
||||
|
||||
# 'getent' function tests: 1
|
||||
'name': 'salt'})
|
||||
|
||||
def test_getent(self):
|
||||
groupobj_mock = MagicMock(
|
||||
return_value=[
|
||||
MockGroupObj('salt', ['WinNT://HOST/steve']),
|
||||
MockGroupObj('salty', ['WinNT://HOST/spongebob'])])
|
||||
mock_g_to_g = MagicMock(side_effect=[1, 2])
|
||||
with patch.object(win_groupadd, '_get_all_groups', groupobj_mock),\
|
||||
patch.dict(win_groupadd.__salt__, {'file.group_to_gid': mock_g_to_g}):
|
||||
self.assertListEqual(
|
||||
win_groupadd.getent(),
|
||||
[
|
||||
{'gid': 1, 'members': ['HOST\\steve'], 'name': 'salt', 'passwd': 'x'},
|
||||
{'gid': 2, 'members': ['HOST\\spongebob'], 'name': 'salty', 'passwd': 'x'}
|
||||
])
|
||||
|
||||
def test_getent_context(self):
|
||||
'''
|
||||
Test if it return info on all groups
|
||||
Test group.getent is using the values in __context__
|
||||
'''
|
||||
with patch.dict(win_groupadd.__context__, {'group.getent': True}):
|
||||
self.assertTrue(win_groupadd.getent())
|
||||
|
||||
# 'adduser' function tests: 1
|
||||
|
||||
def test_adduser(self):
|
||||
'''
|
||||
Test if it add a user to a group
|
||||
Test adding a user to a group
|
||||
'''
|
||||
with patch(win_groupadd.win32.client, 'flag', None):
|
||||
self.assertDictEqual(win_groupadd.adduser('dc=foo', 'dc=\\username'),
|
||||
{'changes': {'Users Added': ['dc=\\username']},
|
||||
'comment': '', 'name': 'dc=foo', 'result': True})
|
||||
groupobj_mock = MagicMock(return_value=MockGroupObj('foo', ['WinNT://HOST/steve']))
|
||||
with patch.object(win_groupadd, '_get_group_object', groupobj_mock), \
|
||||
patch.object(salt.utils.win_functions, 'get_sam_name', sam_mock):
|
||||
self.assertDictEqual(
|
||||
win_groupadd.adduser('foo', 'spongebob'),
|
||||
{'changes': {'Users Added': ['HOST\\spongebob']},
|
||||
'comment': '',
|
||||
'name': 'foo',
|
||||
'result': True})
|
||||
|
||||
with patch(win_groupadd.win32.client, 'flag', 1):
|
||||
comt = ('Failed to add dc=\\username to group dc=foo. C')
|
||||
self.assertDictEqual(win_groupadd.adduser('dc=foo', 'dc=\\username'),
|
||||
{'changes': {'Users Added': []}, 'name': 'dc=foo',
|
||||
'comment': comt, 'result': False})
|
||||
def test_adduser_already_exists(self):
|
||||
'''
|
||||
Test adding a user that already exists
|
||||
'''
|
||||
groupobj_mock = MagicMock(return_value=MockGroupObj('foo', ['WinNT://HOST/steve']))
|
||||
with patch.object(win_groupadd, '_get_group_object', groupobj_mock), \
|
||||
patch.object(salt.utils.win_functions, 'get_sam_name', sam_mock):
|
||||
self.assertDictEqual(
|
||||
win_groupadd.adduser('foo', 'steve'),
|
||||
{'changes': {'Users Added': []},
|
||||
'comment': 'User HOST\\steve is already a member of foo',
|
||||
'name': 'foo',
|
||||
'result': None})
|
||||
|
||||
# 'deluser' function tests: 1
|
||||
def test_adduser_error(self):
|
||||
'''
|
||||
Test adding a user and encountering an error
|
||||
'''
|
||||
# Create mock group object with mocked Add function which raises the
|
||||
# exception we need in order to test the error case.
|
||||
class GroupObj(MockGroupObj):
|
||||
def Add(self, name):
|
||||
raise PYWINTYPES_ERROR
|
||||
|
||||
groupobj_mock = MagicMock(return_value=GroupObj('foo', ['WinNT://HOST/steve']))
|
||||
with patch.object(win_groupadd, '_get_group_object', groupobj_mock), \
|
||||
patch.object(salt.utils.win_functions, 'get_sam_name', sam_mock):
|
||||
self.assertDictEqual(
|
||||
win_groupadd.adduser('foo', 'username'),
|
||||
{'changes': {'Users Added': []},
|
||||
'name': 'foo',
|
||||
'comment': 'Failed to add HOST\\username to group foo. C',
|
||||
'result': False})
|
||||
|
||||
def test_adduser_group_does_not_exist(self):
|
||||
groupobj_mock = MagicMock(side_effect=PYWINTYPES_ERROR)
|
||||
with patch.object(win_groupadd, '_get_group_object', groupobj_mock), \
|
||||
patch.object(salt.utils.win_functions, 'get_sam_name', sam_mock):
|
||||
self.assertDictEqual(
|
||||
win_groupadd.adduser('foo', 'spongebob'),
|
||||
{'changes': {'Users Added': []},
|
||||
'name': 'foo',
|
||||
'comment': 'Failure accessing group foo. C',
|
||||
'result': False})
|
||||
|
||||
def test_deluser(self):
|
||||
'''
|
||||
Test if it remove a user to a group
|
||||
Test removing a user from a group
|
||||
'''
|
||||
ret = {'changes': {'Users Removed': []},
|
||||
'comment': 'User dc=\\username is not a member of dc=foo',
|
||||
'name': 'dc=foo', 'result': None}
|
||||
# Test removing a user
|
||||
groupobj_mock = MagicMock(return_value=MockGroupObj('foo', ['WinNT://HOST/spongebob']))
|
||||
with patch.object(win_groupadd, '_get_group_object', groupobj_mock), \
|
||||
patch.object(salt.utils.win_functions, 'get_sam_name', sam_mock):
|
||||
ret = {'changes': {'Users Removed': ['spongebob']},
|
||||
'comment': '',
|
||||
'name': 'foo',
|
||||
'result': True}
|
||||
self.assertDictEqual(win_groupadd.deluser('foo', 'spongebob'), ret)
|
||||
|
||||
self.assertDictEqual(win_groupadd.deluser('dc=foo', 'dc=\\username'),
|
||||
ret)
|
||||
def test_deluser_no_user(self):
|
||||
'''
|
||||
Test removing a user from a group and that user is not a member of the
|
||||
group
|
||||
'''
|
||||
groupobj_mock = MagicMock(return_value=MockGroupObj('foo', ['WinNT://HOST/steve']))
|
||||
with patch.object(win_groupadd, '_get_group_object', groupobj_mock), \
|
||||
patch.object(salt.utils.win_functions, 'get_sam_name', sam_mock):
|
||||
ret = {'changes': {'Users Removed': []},
|
||||
'comment': 'User spongebob is not a member of foo',
|
||||
'name': 'foo',
|
||||
'result': None}
|
||||
self.assertDictEqual(win_groupadd.deluser('foo', 'spongebob'), ret)
|
||||
|
||||
# 'members' function tests: 1
|
||||
def test_deluser_error(self):
|
||||
'''
|
||||
Test removing a user and encountering an error
|
||||
'''
|
||||
class GroupObj(MockGroupObj):
|
||||
def Remove(self, name):
|
||||
raise PYWINTYPES_ERROR
|
||||
|
||||
groupobj_mock = MagicMock(return_value=GroupObj('foo', ['WinNT://HOST/spongebob']))
|
||||
with patch.object(win_groupadd, '_get_group_object', groupobj_mock), \
|
||||
patch.object(salt.utils.win_functions, 'get_sam_name', sam_mock):
|
||||
self.assertDictEqual(
|
||||
win_groupadd.deluser('foo', 'spongebob'),
|
||||
{'changes': {'Users Removed': []},
|
||||
'name': 'foo',
|
||||
'comment': 'Failed to remove spongebob from group foo. C',
|
||||
'result': False})
|
||||
|
||||
def test_deluser_group_does_not_exist(self):
|
||||
groupobj_mock = MagicMock(side_effect=PYWINTYPES_ERROR)
|
||||
with patch.object(win_groupadd, '_get_group_object', groupobj_mock), \
|
||||
patch.object(salt.utils.win_functions, 'get_sam_name', sam_mock):
|
||||
self.assertDictEqual(
|
||||
win_groupadd.deluser('foo', 'spongebob'),
|
||||
{'changes': {'Users Removed': []},
|
||||
'name': 'foo',
|
||||
'comment': 'Failure accessing group foo. C',
|
||||
'result': False})
|
||||
|
||||
def test_members(self):
|
||||
'''
|
||||
Test if it remove a user to a group
|
||||
Test adding a list of members to a group, all existing users removed
|
||||
'''
|
||||
comment = ['Failure accessing group dc=foo. C']
|
||||
ret = {'name': 'dc=foo', 'result': False, 'comment': comment,
|
||||
'changes': {'Users Added': [], 'Users Removed': []}}
|
||||
groupobj_mock = MagicMock(return_value=MockGroupObj('foo', ['WinNT://HOST/steve']))
|
||||
with patch.object(win_groupadd, '_get_group_object', groupobj_mock), \
|
||||
patch.object(salt.utils.win_functions, 'get_sam_name', sam_mock):
|
||||
self.assertDictEqual(
|
||||
win_groupadd.members('foo', 'spongebob,patrick,squidward'),
|
||||
{'changes': {
|
||||
'Users Added': ['HOST\\patrick', 'HOST\\spongebob', 'HOST\\squidward'],
|
||||
'Users Removed': ['HOST\\steve']
|
||||
},
|
||||
'comment': [],
|
||||
'name': 'foo',
|
||||
'result': True})
|
||||
|
||||
with patch(win_groupadd.win32.client, 'flag', 2):
|
||||
self.assertDictEqual(win_groupadd.members
|
||||
('dc=foo', 'dc=\\user1,dc=\\user2,dc=\\user3'),
|
||||
ret)
|
||||
def test_members_correct_membership(self):
|
||||
'''
|
||||
Test adding a list of users where the list of users already exists
|
||||
'''
|
||||
members_list = ['WinNT://HOST/spongebob',
|
||||
'WinNT://HOST/squidward',
|
||||
'WinNT://HOST/patrick']
|
||||
groupobj_mock = MagicMock(return_value=MockGroupObj('foo', members_list))
|
||||
with patch.object(win_groupadd, '_get_group_object', groupobj_mock), \
|
||||
patch.object(salt.utils.win_functions, 'get_sam_name', sam_mock):
|
||||
self.assertDictEqual(
|
||||
win_groupadd.members('foo', 'spongebob,patrick,squidward'),
|
||||
{'changes': {'Users Added': [], 'Users Removed': []},
|
||||
'comment': ['foo membership is correct'],
|
||||
'name': 'foo',
|
||||
'result': None})
|
||||
|
||||
with patch(win_groupadd.win32.client, 'flag', 1):
|
||||
comment = ['Failed to add dc=\\user2 to dc=foo. C',
|
||||
'Failed to remove dc=\\user1 from dc=foo. C']
|
||||
ret.update({'comment': comment, 'result': False})
|
||||
self.assertDictEqual(win_groupadd.members('dc=foo', 'dc=\\user2'), ret)
|
||||
def test_members_group_does_not_exist(self):
|
||||
'''
|
||||
Test adding a list of users where the group does not exist
|
||||
'''
|
||||
groupobj_mock = MagicMock(side_effect=PYWINTYPES_ERROR)
|
||||
with patch.object(win_groupadd, '_get_group_object', groupobj_mock), \
|
||||
patch.object(salt.utils.win_functions, 'get_sam_name', sam_mock):
|
||||
self.assertDictEqual(
|
||||
win_groupadd.members('foo', 'spongebob'),
|
||||
{'changes': {'Users Added': [], 'Users Removed': []},
|
||||
'comment': ['Failure accessing group foo. C'],
|
||||
'name': 'foo',
|
||||
'result': False})
|
||||
|
||||
with patch(win_groupadd.win32.client, 'flag', None):
|
||||
comment = ['dc=foo membership is correct']
|
||||
ret.update({'comment': comment, 'result': None})
|
||||
self.assertDictEqual(win_groupadd.members('dc=foo', 'dc=\\user1'), ret)
|
||||
def test_members_fail_to_remove(self):
|
||||
'''
|
||||
Test adding a list of members and fail to remove members not in the list
|
||||
'''
|
||||
class GroupObj(MockGroupObj):
|
||||
def Remove(self, name):
|
||||
raise PYWINTYPES_ERROR
|
||||
|
||||
groupobj_mock = MagicMock(return_value=GroupObj('foo', ['WinNT://HOST/spongebob']))
|
||||
with patch.object(win_groupadd, '_get_group_object', groupobj_mock), \
|
||||
patch.object(salt.utils.win_functions, 'get_sam_name', sam_mock):
|
||||
self.assertDictEqual(
|
||||
win_groupadd.members('foo', 'patrick'),
|
||||
{'changes': {'Users Added': ['HOST\\patrick'], 'Users Removed': []},
|
||||
'comment': ['Failed to remove HOST\\spongebob from foo. C'],
|
||||
'name': 'foo',
|
||||
'result': False})
|
||||
|
||||
def test_members_fail_to_add(self):
|
||||
'''
|
||||
Test adding a list of members and failing to add
|
||||
'''
|
||||
class GroupObj(MockGroupObj):
|
||||
def Add(self, name):
|
||||
raise PYWINTYPES_ERROR
|
||||
|
||||
groupobj_mock = MagicMock(return_value=GroupObj('foo', ['WinNT://HOST/spongebob']))
|
||||
with patch.object(win_groupadd, '_get_group_object', groupobj_mock), \
|
||||
patch.object(salt.utils.win_functions, 'get_sam_name', sam_mock):
|
||||
self.assertDictEqual(
|
||||
win_groupadd.members('foo', 'patrick'),
|
||||
{'changes': {'Users Added': [], 'Users Removed': ['HOST\\spongebob']},
|
||||
'comment': ['Failed to add HOST\\patrick to foo. C'],
|
||||
'name': 'foo',
|
||||
'result': False})
|
||||
|
||||
def test_list_groups(self):
|
||||
'''
|
||||
Test that list groups returns a list of groups by name
|
||||
'''
|
||||
groupobj_mock = MagicMock(
|
||||
return_value=[
|
||||
MockGroupObj('salt', ['WinNT://HOST/steve']),
|
||||
MockGroupObj('salty', ['WinNT://HOST/Administrator'])])
|
||||
with patch.object(win_groupadd, '_get_all_groups', groupobj_mock):
|
||||
self.assertListEqual(win_groupadd.list_groups(),
|
||||
['salt', 'salty'])
|
||||
|
||||
def test_list_groups_context(self):
|
||||
'''
|
||||
Test group.list_groups is using the values in __context__
|
||||
'''
|
||||
with patch.dict(win_groupadd.__context__, {'group.list_groups': True}):
|
||||
self.assertTrue(win_groupadd.list_groups())
|
||||
|
@ -814,7 +814,8 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
|
||||
ret.update({
|
||||
'comment': comt,
|
||||
'result': None,
|
||||
'pchanges': p_chg
|
||||
'pchanges': p_chg,
|
||||
'changes': {'/etc/grub.conf': {'directory': 'new'}}
|
||||
})
|
||||
self.assertDictEqual(filestate.directory(name,
|
||||
user=user,
|
||||
@ -825,7 +826,7 @@ class TestFileState(TestCase, LoaderModuleMockMixin):
|
||||
with patch.object(os.path, 'isdir', mock_f):
|
||||
comt = ('No directory to create {0} in'
|
||||
.format(name))
|
||||
ret.update({'comment': comt, 'result': False})
|
||||
ret.update({'comment': comt, 'result': False, 'changes': {}})
|
||||
self.assertDictEqual(filestate.directory
|
||||
(name, user=user, group=group),
|
||||
ret)
|
||||
|
@ -313,21 +313,21 @@ class PyDSLRendererTestCase(CommonTestCaseBoilerplate):
|
||||
- cwd: /
|
||||
.Y:
|
||||
cmd.run:
|
||||
- name: echo Y >> {1}
|
||||
- name: echo Y >> {0}
|
||||
- cwd: /
|
||||
.Z:
|
||||
cmd.run:
|
||||
- name: echo Z >> {2}
|
||||
- name: echo Z >> {0}
|
||||
- cwd: /
|
||||
'''.format(output, output, output)))
|
||||
'''.format(output.replace('\\', '/'))))
|
||||
write_to(os.path.join(dirpath, 'yyy.sls'), textwrap.dedent('''\
|
||||
#!pydsl|stateconf -ps
|
||||
|
||||
__pydsl__.set(ordered=True)
|
||||
state('.D').cmd.run('echo D >> {0}', cwd='/')
|
||||
state('.E').cmd.run('echo E >> {1}', cwd='/')
|
||||
state('.F').cmd.run('echo F >> {2}', cwd='/')
|
||||
'''.format(output, output, output)))
|
||||
state('.E').cmd.run('echo E >> {0}', cwd='/')
|
||||
state('.F').cmd.run('echo F >> {0}', cwd='/')
|
||||
'''.format(output.replace('\\', '/'))))
|
||||
|
||||
write_to(os.path.join(dirpath, 'aaa.sls'), textwrap.dedent('''\
|
||||
#!pydsl|stateconf -ps
|
||||
@ -343,9 +343,9 @@ class PyDSLRendererTestCase(CommonTestCaseBoilerplate):
|
||||
__pydsl__.set(ordered=True)
|
||||
|
||||
state('.A').cmd.run('echo A >> {0}', cwd='/')
|
||||
state('.B').cmd.run('echo B >> {1}', cwd='/')
|
||||
state('.C').cmd.run('echo C >> {2}', cwd='/')
|
||||
'''.format(output, output, output)))
|
||||
state('.B').cmd.run('echo B >> {0}', cwd='/')
|
||||
state('.C').cmd.run('echo C >> {0}', cwd='/')
|
||||
'''.format(output.replace('\\', '/'))))
|
||||
|
||||
self.state_highstate({'base': ['aaa']}, dirpath)
|
||||
with salt.utils.fopen(output, 'r') as f:
|
||||
@ -365,26 +365,29 @@ class PyDSLRendererTestCase(CommonTestCaseBoilerplate):
|
||||
)
|
||||
)
|
||||
try:
|
||||
# The Windows shell will include any spaces before the redirect
|
||||
# in the text that is redirected.
|
||||
# For example: echo hello > test.txt will contain "hello "
|
||||
write_to(os.path.join(dirpath, 'aaa.sls'), textwrap.dedent('''\
|
||||
#!pydsl
|
||||
|
||||
__pydsl__.set(ordered=True)
|
||||
A = state('A')
|
||||
A.cmd.run('echo hehe > {0}/zzz.txt', cwd='/')
|
||||
A.file.managed('{1}/yyy.txt', source='salt://zzz.txt')
|
||||
A.cmd.run('echo hehe>{0}/zzz.txt', cwd='/')
|
||||
A.file.managed('{0}/yyy.txt', source='salt://zzz.txt')
|
||||
A()
|
||||
A()
|
||||
|
||||
state().cmd.run('echo hoho >> {2}/yyy.txt', cwd='/')
|
||||
state().cmd.run('echo hoho>>{0}/yyy.txt', cwd='/')
|
||||
|
||||
A.file.managed('{3}/xxx.txt', source='salt://zzz.txt')
|
||||
A.file.managed('{0}/xxx.txt', source='salt://zzz.txt')
|
||||
A()
|
||||
'''.format(dirpath, dirpath, dirpath, dirpath)))
|
||||
'''.format(dirpath.replace('\\', '/'))))
|
||||
self.state_highstate({'base': ['aaa']}, dirpath)
|
||||
with salt.utils.fopen(os.path.join(dirpath, 'yyy.txt'), 'rt') as f:
|
||||
self.assertEqual(f.read(), 'hehe\nhoho\n')
|
||||
self.assertEqual(f.read(), 'hehe' + os.linesep + 'hoho' + os.linesep)
|
||||
with salt.utils.fopen(os.path.join(dirpath, 'xxx.txt'), 'rt') as f:
|
||||
self.assertEqual(f.read(), 'hehe\n')
|
||||
self.assertEqual(f.read(), 'hehe' + os.linesep)
|
||||
finally:
|
||||
shutil.rmtree(dirpath, ignore_errors=True)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user