Skip to content

Commit 1d37a3e

Browse files
committed
Manually merge PR105 to adjust save settings to only save provided values and required default values instead of all defaults. Also adds unit tests to the basic module functionality and some comments on the urge to fix the ill-named check_types function from parser, which really makes in-line changes to the passed keywords dictionary argument.
git-svn-id: svn+ssh://svn.code.sf.net/p/migrid/code/trunk@6109 b75ad72c-e7d7-11dd-a971-7dbc132099af
1 parent b6b9e1c commit 1d37a3e

File tree

2 files changed

+172
-7
lines changed

2 files changed

+172
-7
lines changed

mig/shared/settings.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# --- BEGIN_HEADER ---
55
#
66
# settings - helpers for handling user settings
7-
# Copyright (C) 2003-2021 The MiG Project lead by Brian Vinter
7+
# Copyright (C) 2003-2024 The MiG Project lead by Brian Vinter
88
#
99
# This file is part of MiG.
1010
#
@@ -27,6 +27,7 @@
2727

2828
from __future__ import absolute_import
2929

30+
import copy
3031
import datetime
3132
import os
3233

@@ -62,26 +63,30 @@ def parse_and_save_pickle(source, destination, keywords, client_id,
6263
client_dir = client_id_dir(client_id)
6364
result = parse(source, strip_space, strip_comments)
6465

65-
(status, parsemsg) = check_types(result, keywords, configuration)
66+
# TODO: rename or split up check_types to avoid or clarify side-effects
67+
# NOTE: check_types also fills parsed results into the given keywords dict!
68+
parsed = copy.deepcopy(keywords)
69+
(status, parsemsg) = check_types(result, parsed, configuration)
6670

6771
try:
6872
os.remove(source)
6973
except Exception as err:
7074
msg = 'Exception removing temporary file %s, %s'\
7175
% (source, err)
7276

73-
# should we exit because of this? o.reply_and_exit(o.ERROR)
74-
7577
if not status:
7678
msg = 'Parse failed (typecheck) %s' % parsemsg
7779
return (False, msg)
7880

7981
new_dict = {}
8082

81-
# move parseresult to a dictionary
83+
# copy parsed result and required default values to a new flat dictionary
8284

83-
for (key, value_dict) in keywords.iteritems():
84-
new_dict[key] = value_dict['Value']
85+
for key in keywords:
86+
if keywords[key].get('Required', True):
87+
new_dict[key] = parsed[key]['Value']
88+
elif parsed[key]['Value'] != keywords[key]['Value']:
89+
new_dict[key] = parsed[key]['Value']
8590
# apply any overrides
8691
for key in overrides:
8792
new_dict[key] = overrides[key]

tests/test_mig_shared_settings.py

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
# -*- coding: utf-8 -*-
2+
#
3+
# --- BEGIN_HEADER ---
4+
#
5+
# test_mig_shared_settings - unit test of the corresponding mig shared module
6+
# Copyright (C) 2003-2024 The MiG Project by the Science HPC Center at UCPH
7+
#
8+
# This file is part of MiG.
9+
#
10+
# MiG is free software: you can redistribute it and/or modify
11+
# it under the terms of the GNU General Public License as published by
12+
# the Free Software Foundation; either version 2 of the License, or
13+
# (at your option) any later version.
14+
#
15+
# MiG is distributed in the hope that it will be useful,
16+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
17+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18+
# GNU General Public License for more details.
19+
#
20+
# You should have received a copy of the GNU General Public License
21+
# along with this program; if not, write to the Free Software
22+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
23+
# USA.
24+
#
25+
# --- END_HEADER ---
26+
#
27+
28+
"""Unit tests for the migrid module pointed to in the filename"""
29+
30+
import os
31+
import sys
32+
33+
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__))))
34+
35+
from tests.support import TEST_OUTPUT_DIR, MigTestCase, FakeConfiguration, \
36+
cleanpath, testmain
37+
from mig.shared.settings import load_settings, update_settings, \
38+
parse_and_save_settings
39+
40+
DUMMY_USER = "dummy-user"
41+
DUMMY_SETTINGS_DIR = 'dummy_user_settings'
42+
DUMMY_SETTINGS_PATH = os.path.join(TEST_OUTPUT_DIR, DUMMY_SETTINGS_DIR)
43+
DUMMY_SYSTEM_FILES_DIR = 'dummy_system_files'
44+
DUMMY_SYSTEM_FILES_PATH = os.path.join(TEST_OUTPUT_DIR, DUMMY_SYSTEM_FILES_DIR)
45+
DUMMY_TMP_DIR = 'dummy_tmp'
46+
DUMMY_TMP_FILE = 'settings.mRSL'
47+
DUMMY_TMP_PATH = os.path.join(TEST_OUTPUT_DIR, DUMMY_TMP_DIR)
48+
DUMMY_MRSL_PATH = os.path.join(DUMMY_TMP_PATH, DUMMY_TMP_FILE)
49+
50+
DUMMY_USER_INTERFACE = ['V3', 'V42']
51+
DUMMY_DEFAULT_UI = 'V42'
52+
DUMMY_INIT_MRSL = """
53+
::EMAIL::
54+
john@doe.org
55+
56+
::SITE_USER_MENU::
57+
sharelinks
58+
people
59+
peers
60+
"""
61+
DUMMY_UPDATE_MRSL = """
62+
::EMAIL::
63+
jane@doe.org
64+
65+
::SITE_USER_MENU::
66+
people
67+
"""
68+
DUMMY_CONF = FakeConfiguration(user_settings=DUMMY_SETTINGS_PATH,
69+
mig_system_files=DUMMY_SYSTEM_FILES_PATH,
70+
user_interface=DUMMY_USER_INTERFACE,
71+
new_user_default_ui=DUMMY_DEFAULT_UI)
72+
73+
74+
class MigSharedSettings(MigTestCase):
75+
"""Wrap unit tests for the corresponding module"""
76+
77+
def test_settings_save_load(self):
78+
os.makedirs(os.path.join(DUMMY_SETTINGS_PATH, DUMMY_USER))
79+
cleanpath(DUMMY_SETTINGS_DIR, self)
80+
os.makedirs(os.path.join(DUMMY_SYSTEM_FILES_PATH, DUMMY_USER))
81+
cleanpath(DUMMY_SYSTEM_FILES_DIR, self)
82+
os.makedirs(os.path.join(DUMMY_TMP_PATH))
83+
cleanpath(DUMMY_TMP_DIR, self)
84+
85+
with open(DUMMY_MRSL_PATH, 'w') as mrsl_fd:
86+
mrsl_fd.write(DUMMY_INIT_MRSL)
87+
save_status, save_msg = parse_and_save_settings(
88+
DUMMY_MRSL_PATH, DUMMY_USER, DUMMY_CONF)
89+
self.assertTrue(save_status)
90+
self.assertFalse(save_msg)
91+
92+
saved_path = os.path.join(DUMMY_SETTINGS_PATH, DUMMY_USER, 'settings')
93+
self.assertTrue(os.path.exists(saved_path))
94+
95+
settings = load_settings(DUMMY_USER, DUMMY_CONF)
96+
# NOTE: updated should be a non-empty dict at this point
97+
self.assertTrue(isinstance(settings, dict))
98+
self.assertEqual(settings['EMAIL'], ['john@doe.org'])
99+
self.assertEqual(settings['SITE_USER_MENU'],
100+
['sharelinks', 'people', 'peers'])
101+
# NOTE: we no longer auto save default values for optional vars
102+
for key in settings.keys():
103+
self.assertTrue(key in ['EMAIL', 'SITE_USER_MENU'])
104+
# Any saved USER_INTERFACE value must match configured default if set
105+
self.assertEqual(settings.get('USER_INTERFACE', DUMMY_DEFAULT_UI),
106+
DUMMY_DEFAULT_UI)
107+
108+
def test_settings_replace(self):
109+
os.makedirs(os.path.join(DUMMY_SETTINGS_PATH, DUMMY_USER))
110+
cleanpath(DUMMY_SETTINGS_DIR, self)
111+
os.makedirs(os.path.join(DUMMY_SYSTEM_FILES_PATH, DUMMY_USER))
112+
cleanpath(DUMMY_SYSTEM_FILES_DIR, self)
113+
os.makedirs(os.path.join(DUMMY_TMP_PATH))
114+
cleanpath(DUMMY_TMP_DIR, self)
115+
116+
with open(DUMMY_MRSL_PATH, 'w') as mrsl_fd:
117+
mrsl_fd.write(DUMMY_INIT_MRSL)
118+
save_status, save_msg = parse_and_save_settings(
119+
DUMMY_MRSL_PATH, DUMMY_USER, DUMMY_CONF)
120+
self.assertTrue(save_status)
121+
self.assertFalse(save_msg)
122+
123+
with open(DUMMY_MRSL_PATH, 'w') as mrsl_fd:
124+
mrsl_fd.write(DUMMY_UPDATE_MRSL)
125+
save_status, save_msg = parse_and_save_settings(
126+
DUMMY_MRSL_PATH, DUMMY_USER, DUMMY_CONF)
127+
self.assertTrue(save_status)
128+
self.assertFalse(save_msg)
129+
130+
updated = load_settings(DUMMY_USER, DUMMY_CONF)
131+
# NOTE: updated should be a non-empty dict at this point
132+
self.assertTrue(isinstance(updated, dict))
133+
self.assertEqual(updated['EMAIL'], ['jane@doe.org'])
134+
self.assertEqual(updated['SITE_USER_MENU'], ['people'])
135+
136+
def test_update_settings(self):
137+
os.makedirs(os.path.join(DUMMY_SETTINGS_PATH, DUMMY_USER))
138+
cleanpath(DUMMY_SETTINGS_DIR, self)
139+
os.makedirs(os.path.join(DUMMY_SYSTEM_FILES_PATH, DUMMY_USER))
140+
cleanpath(DUMMY_SYSTEM_FILES_DIR, self)
141+
os.makedirs(os.path.join(DUMMY_TMP_PATH))
142+
cleanpath(DUMMY_TMP_DIR, self)
143+
144+
with open(DUMMY_MRSL_PATH, 'w') as mrsl_fd:
145+
mrsl_fd.write(DUMMY_INIT_MRSL)
146+
save_status, save_msg = parse_and_save_settings(
147+
DUMMY_MRSL_PATH, DUMMY_USER, DUMMY_CONF)
148+
self.assertTrue(save_status)
149+
self.assertFalse(save_msg)
150+
151+
changes = {'EMAIL': ['john@doe.org', 'jane@doe.org']}
152+
defaults = {}
153+
updated = update_settings(DUMMY_USER, DUMMY_CONF, changes, defaults)
154+
# NOTE: updated should be a non-empty dict at this point
155+
self.assertTrue(isinstance(updated, dict))
156+
self.assertEqual(updated['EMAIL'], ['john@doe.org', 'jane@doe.org'])
157+
158+
159+
if __name__ == '__main__':
160+
testmain()

0 commit comments

Comments
 (0)