2012-09-26 04:57:16 +04:00
# Unix SMB/CIFS implementation.
# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2012
#
# Tests for documentation.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program 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. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
""" Tests for presence of documentation. """
import samba
import samba . tests
import os
import re
import subprocess
2013-12-24 06:33:42 +04:00
import xml . etree . ElementTree as ET
2012-09-26 04:57:16 +04:00
2018-07-30 09:20:39 +03:00
2013-12-24 06:33:42 +04:00
class TestCase ( samba . tests . TestCaseInTempDir ) :
2012-09-26 04:57:16 +04:00
def _format_message ( self , parameters , message ) :
parameters = list ( parameters )
2015-07-23 17:25:45 +03:00
parameters = map ( str , parameters )
2012-09-26 04:57:16 +04:00
parameters . sort ( )
return message + ' \n \n %s ' % ( ' \n ' . join ( parameters ) )
2014-12-14 23:03:28 +03:00
2012-09-26 04:57:16 +04:00
def get_documented_parameters ( sourcedir ) :
2012-10-19 11:16:55 +04:00
path = os . path . join ( sourcedir , " bin " , " default " , " docs-xml " , " smbdotconf " )
if not os . path . exists ( os . path . join ( path , " parameters.all.xml " ) ) :
raise Exception ( " Unable to find parameters.all.xml " )
2012-09-28 20:52:41 +04:00
try :
2013-12-24 06:33:42 +04:00
p = open ( os . path . join ( path , " parameters.all.xml " ) , ' r ' )
2018-02-14 00:27:52 +03:00
except IOError as e :
2013-12-24 06:33:42 +04:00
raise Exception ( " Error opening parameters file " )
out = p . read ( )
root = ET . fromstring ( out )
for parameter in root :
name = parameter . attrib . get ( ' name ' )
if parameter . attrib . get ( ' removed ' ) == " 1 " :
2018-07-30 09:13:57 +03:00
continue
2013-12-24 06:33:42 +04:00
yield name
syn = parameter . findall ( ' synonym ' )
if syn is not None :
for sy in syn :
yield sy . text
p . close ( )
2012-09-26 04:57:16 +04:00
2014-03-06 02:36:06 +04:00
def get_documented_tuples ( sourcedir , omit_no_default = True ) :
2013-12-24 06:33:42 +04:00
path = os . path . join ( sourcedir , " bin " , " default " , " docs-xml " , " smbdotconf " )
if not os . path . exists ( os . path . join ( path , " parameters.all.xml " ) ) :
raise Exception ( " Unable to find parameters.all.xml " )
try :
p = open ( os . path . join ( path , " parameters.all.xml " ) , ' r ' )
2018-02-14 00:27:52 +03:00
except IOError as e :
2013-12-24 06:33:42 +04:00
raise Exception ( " Error opening parameters file " )
out = p . read ( )
root = ET . fromstring ( out )
for parameter in root :
name = parameter . attrib . get ( " name " )
2014-03-06 02:36:06 +04:00
param_type = parameter . attrib . get ( " type " )
if parameter . attrib . get ( ' removed ' ) == " 1 " :
2018-07-30 09:13:57 +03:00
continue
2013-12-24 06:33:42 +04:00
values = parameter . findall ( " value " )
defaults = [ ]
for value in values :
if value . attrib . get ( " type " ) == " default " :
defaults . append ( value )
2014-03-06 02:36:06 +04:00
default_text = None
2013-12-24 06:33:42 +04:00
if len ( defaults ) == 0 :
2014-03-06 02:36:06 +04:00
if omit_no_default :
continue
2013-12-24 06:33:42 +04:00
elif len ( defaults ) > 1 :
raise Exception ( " More than one default found for parameter %s " % name )
2014-03-06 02:36:06 +04:00
else :
default_text = defaults [ 0 ] . text
2013-12-24 06:33:42 +04:00
if default_text is None :
default_text = " "
context = parameter . attrib . get ( " context " )
2014-03-06 02:36:06 +04:00
yield name , default_text , context , param_type
2013-12-24 06:33:42 +04:00
p . close ( )
2012-09-26 04:57:16 +04:00
2018-07-30 09:20:39 +03:00
2012-09-26 04:57:16 +04:00
class SmbDotConfTests ( TestCase ) :
2013-12-24 06:33:42 +04:00
# defines the cases where the defaults may differ from the documentation
2017-12-20 23:35:54 +03:00
special_cases = set ( [ ' log level ' , ' path ' ,
' panic action ' , ' homedir map ' , ' NIS homedir ' ,
2013-12-24 06:33:42 +04:00
' server string ' , ' netbios name ' , ' socket options ' , ' use mmap ' ,
' ctdbd socket ' , ' printing ' , ' printcap name ' , ' queueresume command ' ,
2018-07-30 09:19:05 +03:00
' queuepause command ' , ' lpresume command ' , ' lppause command ' ,
2014-05-22 13:42:29 +04:00
' lprm command ' , ' lpq command ' , ' print command ' , ' template homedir ' ,
2017-12-20 23:35:54 +03:00
' max open files ' ,
2014-04-28 17:22:34 +04:00
' include system krb5 conf ' , ' rpc server dynamic port range ' ,
' mit kdc command ' ] )
2013-12-24 06:33:42 +04:00
def setUp ( self ) :
super ( SmbDotConfTests , self ) . setUp ( )
# create a minimal smb.conf file for testparm
self . smbconf = os . path . join ( self . tempdir , " paramtestsmb.conf " )
f = open ( self . smbconf , ' w ' )
try :
f . write ( """
[ test ]
path = /
""" )
finally :
f . close ( )
2014-07-03 08:04:06 +04:00
self . blankconf = os . path . join ( self . tempdir , " emptytestsmb.conf " )
f = open ( self . blankconf , ' w ' )
try :
f . write ( " " )
finally :
f . close ( )
2015-07-22 16:16:16 +03:00
self . topdir = os . path . abspath ( samba . source_tree_topdir ( ) )
try :
self . documented = set ( get_documented_parameters ( self . topdir ) )
except :
self . fail ( " Unable to load documented parameters " )
try :
self . defaults = set ( get_documented_tuples ( self . topdir ) )
except :
self . fail ( " Unable to load parameters " )
try :
self . defaults_all = set ( get_documented_tuples ( self . topdir , False ) )
except :
self . fail ( " Unable to load parameters " )
2013-12-24 06:33:42 +04:00
def tearDown ( self ) :
super ( SmbDotConfTests , self ) . tearDown ( )
os . unlink ( self . smbconf )
2014-07-03 08:04:06 +04:00
os . unlink ( self . blankconf )
2013-12-24 06:33:42 +04:00
def test_default_s3 ( self ) :
self . _test_default ( [ ' bin/testparm ' ] )
2014-03-06 01:12:09 +04:00
self . _set_defaults ( [ ' bin/testparm ' ] )
2013-12-24 06:33:42 +04:00
2014-03-06 02:36:06 +04:00
# registry shares appears to need sudo
self . _set_arbitrary ( [ ' bin/testparm ' ] ,
2018-07-30 09:19:21 +03:00
exceptions = [ ' client lanman auth ' ,
2018-08-22 09:27:10 +03:00
' client plaintext auth ' ,
' registry shares ' ,
' smb ports ' ,
' rpc server dynamic port range ' ,
' name resolve order ' ] )
2014-07-03 08:04:06 +04:00
self . _test_empty ( [ ' bin/testparm ' ] )
2014-03-06 02:36:06 +04:00
2013-12-24 06:33:42 +04:00
def test_default_s4 ( self ) :
self . _test_default ( [ ' bin/samba-tool ' , ' testparm ' ] )
2014-03-06 01:12:09 +04:00
self . _set_defaults ( [ ' bin/samba-tool ' , ' testparm ' ] )
2014-03-14 01:27:54 +04:00
self . _set_arbitrary ( [ ' bin/samba-tool ' , ' testparm ' ] ,
2018-07-30 09:19:21 +03:00
exceptions = [ ' smb ports ' ,
2018-08-22 09:27:10 +03:00
' rpc server dynamic port range ' ,
' name resolve order ' ] )
2014-07-03 08:04:06 +04:00
self . _test_empty ( [ ' bin/samba-tool ' , ' testparm ' ] )
2013-12-24 06:33:42 +04:00
def _test_default ( self , program ) :
failset = set ( )
count = 0
2015-07-22 16:16:16 +03:00
for tuples in self . defaults :
2014-03-06 02:36:06 +04:00
param , default , context , param_type = tuples
2017-01-16 14:05:09 +03:00
2013-12-24 06:33:42 +04:00
if param in self . special_cases :
continue
2017-12-20 23:23:24 +03:00
# bad, bad parametric options - we don't have their default values
if ' : ' in param :
continue
2013-12-24 06:33:42 +04:00
section = None
if context == " G " :
section = " global "
elif context == " S " :
section = " test "
else :
2018-07-30 09:13:57 +03:00
self . fail ( " %s has no valid context " % param )
2018-07-30 09:16:12 +03:00
p = subprocess . Popen ( program + [ " -s " ,
self . smbconf ,
" --section-name " ,
section ,
" --parameter-name " ,
param ] ,
stdout = subprocess . PIPE ,
stderr = subprocess . PIPE ,
cwd = self . topdir ) . communicate ( )
2018-04-05 04:48:36 +03:00
result = p [ 0 ] . decode ( ) . upper ( ) . strip ( )
if result != default . upper ( ) :
if not ( result == " " and default == ' " " ' ) :
2013-12-24 06:33:42 +04:00
doc_triple = " %s \n Expected: %s " % ( param , default )
2018-04-05 04:48:36 +03:00
failset . add ( " %s \n Got: %s " % ( doc_triple , result ) )
2013-12-24 06:33:42 +04:00
if len ( failset ) > 0 :
self . fail ( self . _format_message ( failset ,
2018-07-30 09:16:12 +03:00
" Parameters that do not have matching defaults: " ) )
2014-03-06 01:12:09 +04:00
def _set_defaults ( self , program ) :
failset = set ( )
count = 0
2015-07-22 16:16:16 +03:00
for tuples in self . defaults :
2014-03-06 02:36:06 +04:00
param , default , context , param_type = tuples
2014-03-06 01:12:09 +04:00
2017-01-16 14:05:09 +03:00
if param in [ ' printing ' , ' rpc server dynamic port range ' ] :
2014-03-06 01:12:09 +04:00
continue
section = None
if context == " G " :
section = " global "
elif context == " S " :
section = " test "
else :
2018-07-30 09:13:57 +03:00
self . fail ( " %s has no valid context " % param )
2018-07-30 09:16:12 +03:00
p = subprocess . Popen ( program + [ " -s " ,
self . smbconf ,
" --section-name " ,
section ,
" --parameter-name " ,
param ,
" --option " ,
" %s = %s " % ( param , default ) ] ,
stdout = subprocess . PIPE ,
stderr = subprocess . PIPE ,
cwd = self . topdir ) . communicate ( )
2018-04-05 04:48:36 +03:00
result = p [ 0 ] . decode ( ) . upper ( ) . strip ( )
if result != default . upper ( ) :
if not ( result == " " and default == ' " " ' ) :
2014-03-06 01:12:09 +04:00
doc_triple = " %s \n Expected: %s " % ( param , default )
2018-04-05 04:48:36 +03:00
failset . add ( " %s \n Got: %s " % ( doc_triple , result ) )
2014-03-06 01:12:09 +04:00
if len ( failset ) > 0 :
self . fail ( self . _format_message ( failset ,
2018-07-30 09:16:12 +03:00
" Parameters that do not have matching defaults: " ) )
2014-03-06 02:36:06 +04:00
def _set_arbitrary ( self , program , exceptions = None ) :
arbitrary = { ' string ' : ' string ' , ' boolean ' : ' yes ' , ' integer ' : ' 5 ' ,
2015-07-22 11:31:46 +03:00
' boolean-rev ' : ' yes ' ,
2015-07-24 02:28:56 +03:00
' cmdlist ' : ' a b c ' ,
' bytes ' : ' 10 ' ,
' octal ' : ' 0123 ' ,
' ustring ' : ' ustring ' ,
2018-07-30 09:19:05 +03:00
' enum ' : ' ' , ' boolean-auto ' : ' ' , ' char ' : ' a ' , ' list ' : ' a, b, c ' }
2014-07-03 08:04:06 +04:00
opposite_arbitrary = { ' string ' : ' string2 ' , ' boolean ' : ' no ' , ' integer ' : ' 6 ' ,
2015-07-22 11:31:46 +03:00
' boolean-rev ' : ' no ' ,
2015-07-24 02:28:56 +03:00
' cmdlist ' : ' d e f ' ,
' bytes ' : ' 11 ' ,
' octal ' : ' 0567 ' ,
' ustring ' : ' ustring2 ' ,
2018-07-30 09:19:05 +03:00
' enum ' : ' ' , ' boolean-auto ' : ' ' , ' char ' : ' b ' , ' list ' : ' d, e, f ' }
2015-07-22 16:16:16 +03:00
2014-03-06 02:36:06 +04:00
failset = set ( )
count = 0
2015-07-22 16:16:16 +03:00
for tuples in self . defaults_all :
2014-03-06 02:36:06 +04:00
param , default , context , param_type = tuples
2014-03-13 03:24:36 +04:00
if param in [ ' printing ' , ' copy ' , ' include ' , ' log level ' ] :
2014-03-06 02:36:06 +04:00
continue
# currently no easy way to set an arbitrary value for these
if param_type in [ ' enum ' , ' boolean-auto ' ] :
continue
if exceptions is not None :
if param in exceptions :
continue
section = None
if context == " G " :
section = " global "
elif context == " S " :
section = " test "
else :
2018-07-30 09:13:57 +03:00
self . fail ( " %s has no valid context " % param )
2014-03-06 02:36:06 +04:00
value_to_use = arbitrary . get ( param_type )
if value_to_use is None :
self . fail ( " %s has an invalid type " % param )
2018-07-30 09:16:12 +03:00
p = subprocess . Popen ( program + [ " -s " ,
self . smbconf ,
" --section-name " ,
section ,
" --parameter-name " ,
param ,
" --option " ,
" %s = %s " % ( param , value_to_use ) ] ,
stdout = subprocess . PIPE ,
stderr = subprocess . PIPE ,
cwd = self . topdir ) . communicate ( )
2018-04-05 04:48:36 +03:00
result = p [ 0 ] . decode ( ) . upper ( ) . strip ( )
if result != value_to_use . upper ( ) :
2014-03-06 02:36:06 +04:00
# currently no way to distinguish command lists
if param_type == ' list ' :
2018-04-05 04:48:36 +03:00
if " , " . join ( result . split ( ) ) == value_to_use . upper ( ) :
2014-03-06 02:36:06 +04:00
continue
# currently no way to identify octal
if param_type == ' integer ' :
try :
if int ( value_to_use , 8 ) == int ( p [ 0 ] . strip ( ) , 8 ) :
continue
except :
pass
doc_triple = " %s \n Expected: %s " % ( param , value_to_use )
failset . add ( " %s \n Got: %s " % ( doc_triple , p [ 0 ] . upper ( ) . strip ( ) ) )
2014-07-03 08:04:06 +04:00
opposite_value = opposite_arbitrary . get ( param_type )
tempconf = os . path . join ( self . tempdir , " tempsmb.conf " )
g = open ( tempconf , ' w ' )
try :
towrite = section + " \n "
towrite + = param + " = " + opposite_value
g . write ( towrite )
finally :
g . close ( )
2018-07-30 09:16:12 +03:00
p = subprocess . Popen ( program + [ " -s " ,
tempconf ,
" --suppress-prompt " ,
" --option " ,
" %s = %s " % ( param , value_to_use ) ] ,
stdout = subprocess . PIPE ,
stderr = subprocess . PIPE ,
cwd = self . topdir ) . communicate ( )
2014-07-03 08:04:06 +04:00
os . unlink ( tempconf )
# testparm doesn't display a value if they are equivalent
if ( value_to_use . lower ( ) != opposite_value . lower ( ) ) :
2018-04-05 04:48:36 +03:00
for line in p [ 0 ] . decode ( ) . splitlines ( ) :
2014-07-03 08:04:06 +04:00
if not line . strip ( ) . startswith ( param ) :
continue
value_found = line . split ( " = " ) [ 1 ] . upper ( ) . strip ( )
if value_found != value_to_use . upper ( ) :
# currently no way to distinguish command lists
if param_type == ' list ' :
if " , " . join ( value_found . split ( ) ) == value_to_use . upper ( ) :
continue
# currently no way to identify octal
if param_type == ' integer ' :
try :
if int ( value_to_use , 8 ) == int ( value_found , 8 ) :
continue
except :
pass
doc_triple = " %s \n Expected: %s " % ( param , value_to_use )
failset . add ( " %s \n Got: %s " % ( doc_triple , value_found ) )
2014-03-06 02:36:06 +04:00
if len ( failset ) > 0 :
self . fail ( self . _format_message ( failset ,
2018-07-30 09:16:12 +03:00
" Parameters that were unexpectedly not set: " ) )
2014-07-03 08:04:06 +04:00
def _test_empty ( self , program ) :
2018-07-30 09:16:12 +03:00
p = subprocess . Popen ( program + [ " -s " ,
self . blankconf ,
" --suppress-prompt " ] ,
stdout = subprocess . PIPE ,
stderr = subprocess . PIPE ,
cwd = self . topdir ) . communicate ( )
2014-07-03 08:04:06 +04:00
output = " "
2018-04-05 04:48:36 +03:00
for line in p [ 0 ] . decode ( ) . splitlines ( ) :
2014-07-03 08:04:06 +04:00
if line . strip ( ) . startswith ( ' # ' ) :
continue
if line . strip ( ) . startswith ( " idmap config * " ) :
continue
output + = line . strip ( ) . lower ( ) + ' \n '
if output . strip ( ) != ' [global] ' and output . strip ( ) != ' [globals] ' :
self . fail ( " Testparm returned unexpected output on an empty smb.conf. " )