diff --git a/CHANGELOG.md b/CHANGELOG.md index 437f81ad..f4882516 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ Unreleased ---------- - - +**Bugfixes** + - Fixed an issue where `folders.create_folder()` would attempt to use root folder as parent if desired parent + folder wasn't found. Now correctly handles parent folders and raises an error if folder not found. v1.6.3 (2021-09-23) ------------------- diff --git a/src/sasctl/_services/folders.py b/src/sasctl/_services/folders.py index 2c05dec3..9d78546c 100644 --- a/src/sasctl/_services/folders.py +++ b/src/sasctl/_services/folders.py @@ -25,37 +25,43 @@ class Folders(Service): @classmethod @sasctl_command('folders', 'create') def create_folder(cls, name, parent=None, description=None): - """ + """Create a new folder. Parameters ---------- name : str The name of the new folder parent : str or dict, optional - The parent folder for this folder, if any. Can be a folder name, - id, or dict response from `get_folder` + The parent folder for this folder, if any. Can be a folder name, id, or dict response from `get_folder`. + If not specified, new folder will be created under root folder. description : str, optional A description of the folder Returns ------- + RestObj + Details of newly-created folder """ if parent is not None: - parent = cls.get_folder(parent) + parent_obj = cls.get_folder(parent) - if parent is None: - raise ValueError('`parent` folder does not exist') + parent_uri = cls.get_link(parent_obj, 'self') + if parent_uri is None: + raise ValueError("`parent` folder '%s' does not exist." % parent) + parent_uri = parent_uri['uri'] + else: + parent_uri = None body = { 'name': name, 'description': description, - 'folderType': 'folder', - 'parentFolderUri': '/folders/folders/'+parent.id if parent else None, + 'folderType': 'folder' } return cls.post( '/folders', json=body, + params={'parentFolderUri': parent_uri}, headers={'Content-Type': 'application/vnd.sas.content.folder+json'}, ) diff --git a/tests/unit/test_folders.py b/tests/unit/test_folders.py new file mode 100644 index 00000000..bcb90ad9 --- /dev/null +++ b/tests/unit/test_folders.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python +# encoding: utf-8 +# +# Copyright © 2022, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +from unittest import mock + +import pytest +from sasctl.services import folders + + +def test_create_folder_basic(): + """Create a folder with minimal parameters.""" + FOLDER_NAME = 'Spam' + + with mock.patch('sasctl._services.folders.Folders.post') as post: + folders.create_folder(FOLDER_NAME) + + assert post.called + json = post.call_args[1]['json'] + params = post.call_args[1]['params'] + assert json['name'] == FOLDER_NAME + assert json['description'] is None + assert params['parentFolderUri'] is None + + +def test_create_folder_with_desc(): + """Ensure description parameter is passed.""" + FOLDER_NAME = 'Spam' + FOLDER_DESC = 'Created by sasctl testing.' + + with mock.patch('sasctl._services.folders.Folders.post') as post: + folders.create_folder(FOLDER_NAME, description=FOLDER_DESC) + + assert post.called + json = post.call_args[1]['json'] + params = post.call_args[1]['params'] + assert json['name'] == FOLDER_NAME + assert json['description'] == FOLDER_DESC + assert params['parentFolderUri'] is None + + +def test_create_folder_with_parent(): + """Ensure parent folder parameter is handled correctly.""" + from sasctl.core import RestObj + + FOLDER_NAME = 'Spam' + + # Mock response when retrieving parent folder. + PARENT_FOLDER = RestObj({'name': '', 'id': '123', 'links': [ + {'rel': 'self', 'uri': '/folders/somewhere/spam-eggs-spam-spam'} + ]}) + + with mock.patch('sasctl._services.folders.Folders.get_folder', return_value=PARENT_FOLDER): + with mock.patch('sasctl._services.folders.Folders.post') as post: + folders.create_folder(FOLDER_NAME, parent='Doesnt Matter') + + # Should have tried to create folder with correct name and parent URI + assert post.called + json = post.call_args[1]['json'] + params = post.call_args[1]['params'] + assert json['name'] == FOLDER_NAME + assert json['description'] is None + assert params['parentFolderUri'] == PARENT_FOLDER['links'][0]['uri'] + + # If parent folder can't be found, error should be raised + with mock.patch('sasctl._services.folders.Folders.get_folder', return_value=None): + with mock.patch('sasctl._services.folders.Folders.post'): + with pytest.raises(ValueError): + folders.create_folder(FOLDER_NAME, parent='Doesnt Matter')