@@ -229,6 +229,174 @@ def test_validate_proc_type_conventions_known_type_correct_processor_passes(self
229229 result = target .validate_proc_type_conventions (process , "App.munki.recipe" )
230230 self .assertTrue (result )
231231
232+ def test_validate_required_proc_for_types_munki_with_importer_passes (self ):
233+ # Munki recipe with MunkiImporter should pass
234+ process = [{"Processor" : "MunkiImporter" }]
235+ result = target .validate_required_proc_for_types (process , "App.munki.recipe" )
236+ self .assertTrue (result )
237+
238+ def test_validate_required_proc_for_types_munki_without_importer_fails (self ):
239+ # Munki recipe without MunkiImporter should fail
240+ process = [{"Processor" : "URLDownloader" }]
241+ with mock .patch ("builtins.print" ) as mock_print :
242+ result = target .validate_required_proc_for_types (
243+ process , "App.munki.recipe"
244+ )
245+ self .assertFalse (result )
246+ mock_print .assert_called_with (
247+ "App.munki.recipe: Recipe type munki should contain processor MunkiImporter."
248+ )
249+
250+ def test_validate_required_proc_for_types_pkg_with_creator_passes (self ):
251+ # Pkg recipe with PkgCreator should pass
252+ process = [{"Processor" : "PkgCreator" }]
253+ result = target .validate_required_proc_for_types (process , "App.pkg.recipe" )
254+ self .assertTrue (result )
255+
256+ def test_validate_required_proc_for_types_pkg_without_creator_fails (self ):
257+ # Pkg recipe without required processor should fail
258+ process = [{"Processor" : "URLDownloader" }]
259+ with mock .patch ("builtins.print" ) as mock_print :
260+ result = target .validate_required_proc_for_types (process , "App.pkg.recipe" )
261+ self .assertFalse (result )
262+ mock_print .assert_called_with (
263+ "App.pkg.recipe: Recipe type pkg should contain one of these processors: ['AppPkgCreator', 'PkgCreator', 'PkgCopier']."
264+ )
265+
266+ def test_validate_required_proc_for_types_pkg_empty_process_passes (self ):
267+ # Pkg recipe with empty process list should pass (special case)
268+ process = []
269+ result = target .validate_required_proc_for_types (process , "App.pkg.recipe" )
270+ self .assertTrue (result )
271+
272+ def test_validate_required_proc_for_types_jss_with_importer_passes (self ):
273+ # JSS recipe with JSSImporter should pass
274+ process = [{"Processor" : "JSSImporter" }]
275+ result = target .validate_required_proc_for_types (process , "App.jss.recipe" )
276+ self .assertTrue (result )
277+
278+ def test_validate_required_proc_for_types_unknown_type_passes (self ):
279+ # Unknown recipe type should pass (no checks)
280+ process = [{"Processor" : "SomeProcessor" }]
281+ result = target .validate_required_proc_for_types (process , "App.unknown.recipe" )
282+ self .assertTrue (result )
283+
284+ def test_validate_proc_args_valid_arguments_passes (self ):
285+ # Valid arguments for a core processor should pass
286+ # Skip if autopkglib is not available
287+ if not target .HAS_AUTOPKGLIB :
288+ self .skipTest ("AutoPkg library not available" )
289+
290+ # Mock the AutoPkg library functions
291+ mock_proc = mock .Mock ()
292+ mock_proc .input_variables = {"url" : {}, "filename" : {}}
293+
294+ with mock .patch .object (
295+ target , "processor_names" , return_value = ["URLDownloader" ]
296+ ), mock .patch .object (target , "get_processor" , return_value = mock_proc ):
297+ process = [
298+ {
299+ "Processor" : "URLDownloader" ,
300+ "Arguments" : {"url" : "https://example.com/file.dmg" },
301+ }
302+ ]
303+ result = target .validate_proc_args (process , "App.download.recipe" )
304+ self .assertTrue (result )
305+
306+ def test_validate_proc_args_invalid_argument_fails (self ):
307+ # Invalid argument for a core processor should fail
308+ if not target .HAS_AUTOPKGLIB :
309+ self .skipTest ("AutoPkg library not available" )
310+
311+ mock_proc = mock .Mock ()
312+ mock_proc .input_variables = {"url" : {}, "filename" : {}}
313+
314+ with mock .patch .object (
315+ target , "processor_names" , return_value = ["URLDownloader" ]
316+ ), mock .patch .object (
317+ target , "get_processor" , return_value = mock_proc
318+ ), mock .patch (
319+ "builtins.print"
320+ ) as mock_print :
321+ process = [
322+ {
323+ "Processor" : "URLDownloader" ,
324+ "Arguments" : {"invalid_arg" : "value" },
325+ }
326+ ]
327+ result = target .validate_proc_args (process , "App.download.recipe" )
328+ self .assertFalse (result )
329+ # Check that the error message contains the key info
330+ calls = mock_print .call_args_list
331+ self .assertEqual (len (calls ), 2 ) # Error message + suggestion
332+ self .assertIn ("Unknown argument invalid_arg" , str (calls [0 ]))
333+
334+ def test_validate_proc_args_ignored_arguments_passes (self ):
335+ # Ignored arguments like "note" should pass
336+ if not target .HAS_AUTOPKGLIB :
337+ self .skipTest ("AutoPkg library not available" )
338+
339+ mock_proc = mock .Mock ()
340+ mock_proc .input_variables = {"url" : {}, "filename" : {}}
341+
342+ with mock .patch .object (
343+ target , "processor_names" , return_value = ["URLDownloader" ]
344+ ), mock .patch .object (target , "get_processor" , return_value = mock_proc ):
345+ process = [
346+ {
347+ "Processor" : "URLDownloader" ,
348+ "Arguments" : {
349+ "url" : "https://example.com/file.dmg" ,
350+ "note" : "This is a note" ,
351+ },
352+ }
353+ ]
354+ result = target .validate_proc_args (process , "App.download.recipe" )
355+ self .assertTrue (result )
356+
357+ def test_validate_proc_args_non_core_processor_passes (self ):
358+ # Non-core processors should be skipped
359+ if not target .HAS_AUTOPKGLIB :
360+ self .skipTest ("AutoPkg library not available" )
361+
362+ with mock .patch .object (
363+ target , "processor_names" , return_value = ["URLDownloader" ]
364+ ), mock .patch .object (target , "get_processor" , return_value = mock .Mock ()):
365+ process = [
366+ {
367+ "Processor" : "com.github.custom.CustomProcessor" ,
368+ "Arguments" : {"any_arg" : "value" },
369+ }
370+ ]
371+ result = target .validate_proc_args (process , "App.download.recipe" )
372+ self .assertTrue (result )
373+
374+ def test_validate_proc_args_processor_with_no_args_fails (self ):
375+ # Processor that doesn't accept arguments but receives one should fail
376+ if not target .HAS_AUTOPKGLIB :
377+ self .skipTest ("AutoPkg library not available" )
378+
379+ mock_proc = mock .Mock ()
380+ mock_proc .input_variables = {} # No input variables
381+
382+ with mock .patch .object (
383+ target , "processor_names" , return_value = ["StopProcessingIf" ]
384+ ), mock .patch .object (
385+ target , "get_processor" , return_value = mock_proc
386+ ), mock .patch (
387+ "builtins.print"
388+ ) as mock_print :
389+ process = [
390+ {
391+ "Processor" : "StopProcessingIf" ,
392+ "Arguments" : {"invalid_arg" : "value" },
393+ }
394+ ]
395+ result = target .validate_proc_args (process , "App.download.recipe" )
396+ self .assertFalse (result )
397+ calls = mock_print .call_args_list
398+ self .assertGreater (len (calls ), 0 )
399+
232400
233401if __name__ == "__main__" :
234402 unittest .main ()
0 commit comments