def _test_multiprocess_download_to_shared_bundle_cache( self, func, shared_dir, expected_path ): """ Spawns 10 processes and attempts to run the download function simultaneously. It verifies that the process completes without errors, and the expected path of download exists. :param func: Function that downloads a descriptor :param expected_path: The expected path of the descriptor once it is downloaded locally. :param shared_dir: Optional shared directory to which the descriptor has to be downloaded to. """ # skip this test on windows or py2.5 where multiprocessing isn't available # TODO: Test with subprocess instead of multiprocessing. if is_windows() or sys.version_info < (2, 6): return processes = [] errors = [] try: # spawn 10 processes that begin downloading data to the shared path. for x in range(10): process = multiprocessing.Process(target=func, args=(shared_dir,)) process.start() processes.append(process) except Exception as e: errors.append(e) # wait until all processes have finished all_processes_finished = False while not all_processes_finished: time.sleep(0.1) sys.stderr.write(".") all_processes_finished = all( not (process.is_alive()) for process in processes ) # Make sure the number of processes forked are as expected. self.assertEqual( len(processes), 10, "Failed to spawn the expected number of processes." ) # make sure the expected local path exists. self.assertTrue( os.path.exists(expected_path), "Failed to find the shared bundle cache directory for the descriptor on disk.", ) # bit-wise OR the exit codes of all processes. all_processes_exit_code = reduce( lambda x, y: x | y, [proc.exitcode for proc in processes] ) # Make sure none of the child processes had non-zero exit statuses. self.assertEqual( all_processes_exit_code, 0, "Failed to write concurrently to shared bundle cache: %s" % ",".join(errors), )
def test_create_symlink(self): """ Test folder creation for a shot which matches the static folder trigger condition """ self.assertFalse(os.path.exists(self.aaa)) self.assertFalse(os.path.exists(self.aaa_work)) self.assertFalse(os.path.exists(self.aaa_link)) folder.process_filesystem_structure( self.tk, self.shot_aaa["type"], self.shot_aaa["id"], preview=False, engine=None, ) self.assertTrue(os.path.exists(self.aaa)) self.assertTrue(os.path.exists(self.aaa_work)) if not is_windows(): self.assertTrue(os.path.lexists(self.aaa_link)) self.assertTrue(os.path.islink(self.aaa_link)) self.assertEqual(os.readlink(self.aaa_link), "../Stuff/project_code/aaa") else: # no support on windows self.assertFalse(os.path.exists(self.aaa_link))
def test_legacy_global(self): """ tests the global root, 0.17 style """ cache_path = LocalFileStorageManager.get_global_root( LocalFileStorageManager.CACHE, LocalFileStorageManager.CORE_V17 ) persistent_path = LocalFileStorageManager.get_global_root( LocalFileStorageManager.PERSISTENT, LocalFileStorageManager.CORE_V17 ) log_path = LocalFileStorageManager.get_global_root( LocalFileStorageManager.LOGGING, LocalFileStorageManager.CORE_V17 ) if is_macos(): self.assertEqual(cache_path, os.path.expanduser("~/Library/Caches/Shotgun")) self.assertEqual( persistent_path, os.path.expanduser("~/Library/Application Support/Shotgun"), ) self.assertEqual(log_path, os.path.expanduser("~/Library/Logs/Shotgun")) elif is_windows(): app_data = os.environ.get("APPDATA", "APPDATA_NOT_SET") self.assertEqual(cache_path, os.path.join(app_data, "Shotgun")) self.assertEqual(persistent_path, os.path.join(app_data, "Shotgun")) self.assertEqual(log_path, os.path.join(app_data, "Shotgun")) else: # linux self.assertEqual(cache_path, os.path.expanduser("~/.shotgun")) self.assertEqual(persistent_path, os.path.expanduser("~/.shotgun")) self.assertEqual(log_path, os.path.expanduser("~/.shotgun"))
def test_list_field_token(self): """ Test that we can reference list field tokens in the symlink definition """ self.assertFalse(os.path.exists(self.bbb)) self.assertFalse(os.path.exists(self.bbb_work)) self.assertFalse(os.path.exists(self.bbb_link)) folder.process_filesystem_structure( self.tk, self.asset_bbb["type"], self.asset_bbb["id"], preview=False, engine=None, ) self.assertTrue(os.path.exists(self.bbb)) self.assertTrue(os.path.exists(self.bbb_work)) if not is_windows(): self.assertTrue(os.path.lexists(self.bbb_link)) self.assertTrue(os.path.islink(self.bbb_link)) self.assertEqual( os.readlink(self.bbb_link), "../Stuff/project_code/vehicle/bbb" ) else: # no support on windows self.assertFalse(os.path.exists(self.bbb_link))
def test_local_storage_publish(self, create_mock): """ Tests that we generate local file links when publishing to a known storage """ if is_windows(): values = [ r"x:\tmp\win\path\to\file.txt", r"\\server\share\path\to\file.txt", ] else: values = ["/tmp/nix/path/to/file.txt"] # Various paths we support, Unix and Windows styles for local_path in values: publish_data = tank.util.register_publish(self.tk, self.context, local_path, self.name, self.version, dry_run=True) self.assertIsInstance(publish_data, dict) tank.util.register_publish(self.tk, self.context, local_path, self.name, self.version) create_data = create_mock.call_args args, kwargs = create_data sg_dict = args[1] self.assertEqual(sg_dict["path"], {"local_path": local_path}) self.assertTrue("pathcache" not in sg_dict)
def test_failed_file(self, _): """ Test failing opening folder on mac/linux """ if not is_windows(): self.assertRaises(RuntimeError, fs.open_file_browser, self.test_file)
def test_freeform_publish(self, create_mock): """ Tests that we generate url file:// links for freeform paths """ if is_windows(): values = { "C:/path/to/test file.png": { "url": "file:///C:/path/to/test%20file.png", "name": "test file.png", }, "e:/path/to/test file.png": { "url": "file:///E:/path/to/test%20file.png", "name": "test file.png", }, "//path/to/test file.png": { "url": "file://path/to/test%20file.png", "name": "test file.png", }, r"C:\path\to\test file.png": { "url": "file:///C:/path/to/test%20file.png", "name": "test file.png", }, r"e:\path\to\test file.png": { "url": "file:///E:/path/to/test%20file.png", "name": "test file.png", }, r"\\path\to\test file.png": { "url": "file://path/to/test%20file.png", "name": "test file.png", }, } else: values = { "/path/to/test file.png": { "url": "file:///path/to/test%20file.png", "name": "test file.png", } } # Various paths we support, Unix and Windows styles for (local_path, path_dict) in values.items(): publish_data = tank.util.register_publish(self.tk, self.context, local_path, self.name, self.version, dry_run=True) self.assertIsInstance(publish_data, dict) tank.util.register_publish(self.tk, self.context, local_path, self.name, self.version) create_data = create_mock.call_args args, kwargs = create_data sg_dict = args[1] self.assertEqual(sg_dict["path"], path_dict) self.assertTrue("pathcache" not in sg_dict)
def test_get_publish_path_url(self): """ Tests the hook.get_publish_path method for file urls """ hook = sgtk.Hook(parent=self.tk) sg_dict = { "id": 123, "type": "PublishedFile", "code": "foo", "path": { "url": "file:///foo%20/bar.baz", "type": "Attachment", "name": "bar.baz", "link_type": "web", "content_type": None, }, } if is_windows(): expected_path = r"\foo \bar.baz" else: expected_path = "/foo /bar.baz" self.assertEqual(hook.get_publish_path(sg_dict), expected_path) self.assertEqual( hook.get_publish_paths([sg_dict, sg_dict]), [expected_path, expected_path] )
def _jump_to_fs(self): """ Jump from context to FS """ # launch one window for each location on disk paths = self._engine.context.filesystem_locations for disk_location in paths: # get the setting system = sys.platform # run the app if is_linux(): args = ["xdg-open", disk_location] elif is_macos(): args = ['open "%s"', disk_location] elif is_windows(): args = [ "cmd.exe", "/C", "start", '"Folder %s"' % disk_location ] else: raise Exception("Platform '%s' is not supported." % system) exit_code = subprocess.check_output(args, shell=False) if exit_code != 0: self._engine.logger.error("Failed to launch '%s'!", args)
def test_safe_delete_folder_with_file_in_use(self): """ Check that delete folder will delete as much as it can, even when it encounters errors like failures to delete some of the items in the folder """ src_folder = os.path.join( self.util_filesystem_test_folder_location, "delete_folder" ) dst_folder = os.path.join(self.tank_temp, "folder_in_use") shutil.copytree(src_folder, dst_folder) self.assertTrue(os.path.exists(dst_folder)) # open a file in the directory to remove ... with open(os.path.join(dst_folder, "ReadWrite.txt")) as f: # ... and check that a failure occurs fs.safe_delete_folder(dst_folder) if is_windows(): # A failure occurred, folder should still be there self.assertTrue( os.path.exists(dst_folder) ) # on Windows removal of in-use files behaves differently than... else: self.assertFalse( os.path.exists(dst_folder) ) # ... on Unix, see comments for https://docs.python.org/2/library/os.html#os.remove
def test_setup_centralized_project(self, mocked=None): """ Test setting up a Project. """ def mocked_resolve_core_path(core_path): return { "linux2": core_path, "darwin": core_path, "win32": core_path } mocked.side_effect = mocked_resolve_core_path # create new project new_project = { "type": "Project", "id": 1234, "name": "new_project_1234" } self.add_to_sg_mock_db(new_project) # location where the config will be installed new_config_root = os.path.join(self.tank_temp, "new_project_1234_config") # location where the data will be installed os.makedirs(os.path.join(self.tank_temp, "new_project_1234")) command = self.tk.get_command("setup_project") command.set_logger(logging.getLogger("/dev/null")) # Test we can setup a new project and it does not fail. command.execute({ "project_id": new_project["id"], "project_folder_name": "new_project_1234", "config_uri": self.project_config, "config_path_mac": new_config_root if is_macos() else None, "config_path_win": new_config_root if is_windows() else None, "config_path_linux": new_config_root if is_linux() else None, }) # Check we get back our custom primary root name new_pc = tank.pipelineconfig_factory.from_path(new_config_root) self.assertEqual(list(new_pc.get_data_roots().keys()), ["setup_project_root"]) # make sure the fake core didn't get copied across, e.g. that # we didn't localize the setup self.assertFalse( os.path.exists( os.path.join(new_config_root, "install", "core", "bad_path"))) # make sure we have the core location files for this unlocalized setup self.assertTrue( os.path.exists( os.path.join(new_config_root, "install", "core", "core_Darwin.cfg")))
def only_run_on_windows(func): """ Decorator that allows to skip a test if not running on windows. :param func: Function to be decorated. :returns: The decorated function. """ running_nix = not is_windows() return unittest.skipIf(running_nix, "Windows only test.")(func)
def only_run_on_nix(func): """ Decorator that allows to skip a test if not running on linux/macosx. :param func: Function to be decorated. :returns: The decorated function. """ running_windows = is_windows() return unittest.skipIf(running_windows, "Linux/Macosx only test.")(func)
def test_static_tokens(self): definition = "{Sequence}/{Shot}/3d/maya/scenes/{branch}-v{version}.{ext}" if is_windows(): expected = [["\\", "\\3d\\maya\\scenes\\", "-v", "."]] else: expected = [["/", "/3d/maya/scenes/", "-v", "."]] template = TemplatePath(definition, self.keys, root_path="") self.assertEqual(expected, template._static_tokens)
def test_normalize(self): """ Tests get_shotgun_storage_key """ if is_windows(): self.assertEqual(ShotgunPath.normalize("C:/foo\\bar\\"), r"C:\foo\bar") else: self.assertEqual(ShotgunPath.normalize("/foo\\bar/"), "/foo/bar")
def _test_config_locations(self, pc, autogen_files_root, config_files_root): """ Test locations that are reported by the configuration. """ # Pipeline configuration location tests. self.assertEqual(pc.get_path(), autogen_files_root) self.assertEqual( pc.get_yaml_cache_location(), os.path.join(autogen_files_root, "yaml_cache.pickle"), ) self.assertEqual( pc._get_pipeline_config_file_location(), os.path.join( autogen_files_root, "config", "core", "pipeline_configuration.yml" ), ) self.assertEqual( pc._storage_roots.roots_file, os.path.join(autogen_files_root, "config", "core", "roots.yml"), ) self.assertEqual( pc.get_all_os_paths(), tank.util.ShotgunPath( autogen_files_root if is_windows() else None, autogen_files_root if is_linux() else None, autogen_files_root if is_macos() else None, ), ) # Config folder location test. self.assertEqual(pc.get_config_location(), os.path.join(config_files_root)) self.assertEqual( pc.get_core_hooks_location(), os.path.join(config_files_root, "core", "hooks"), ) self.assertEqual( pc.get_schema_config_location(), os.path.join(config_files_root, "core", "schema"), ) self.assertEqual( pc.get_hooks_location(), os.path.join(config_files_root, "hooks") ) self.assertEqual( pc.get_shotgun_menu_cache_location(), os.path.join(autogen_files_root, "cache"), ) self.assertEqual( pc.get_environment_path("test"), os.path.join(config_files_root, "env", "test.yml"), ) self.assertEqual( pc._get_templates_config_location(), os.path.join(config_files_root, "core", "templates.yml"), )
def test_file(self, subprocess_mock): """ Tests opening a file """ fs.open_file_browser(self.test_file) args, kwargs = subprocess_mock.call_args if is_linux(): self.assertEqual(args[0], ["xdg-open", os.path.dirname(self.test_file)]) elif is_macos(): self.assertEqual(args[0], ["open", "-R", self.test_file]) elif is_windows(): self.assertEqual(args[0], ["explorer", "/select,", self.test_file])
def test_project_path_lookup(self): """ Check that a sgtk init works for this path """ # only run this test on windows if is_windows(): # probe a path inside of project test_path = "%s\\%s\\toolkit_test_path" % ( self.STORAGE_ROOT, self.PROJECT_NAME, ) if not os.path.exists(test_path): os.makedirs(test_path) self.assertIsInstance(sgtk.sgtk_from_path(test_path), Tank)
def test_folder(self, subprocess_mock): """ Tests opening a folder """ fs.open_file_browser(self.test_folder) args, kwargs = subprocess_mock.call_args if is_linux(): self.assertEqual(args[0], ["xdg-open", self.test_folder]) elif is_macos(): self.assertEqual(args[0], ["open", self.test_folder]) elif is_windows(): self.assertEqual(args[0], ["cmd.exe", "/C", "start", self.test_folder])
def init_qt_app(self): """ Initializes if not done already the QT Application for the engine. """ """ Ensure the QApplication is initialized """ from sgtk.platform.qt import QtGui self._qt_app = QtGui.QApplication.instance() self._qt_app.setWindowIcon(QtGui.QIcon(self.icon_256)) self._qt_app.setQuitOnLastWindowClosed(False) self._qt_app.setQuitOnLastWindowClosed(False) if self._qt_app_main_window is None: self.log_debug("Initializing main QApplication...") self._qt_app_main_window = QtGui.QMainWindow() # parent the main window under the Blender main window if is_windows(): import ctypes hwnd = ctypes.windll.user32.GetActiveWindow() if hwnd: self._qt_app_main_window.create(hwnd) self._qt_app_central_widget = QtGui.QWidget() self._qt_app_main_window.setCentralWidget( self._qt_app_central_widget) # set up the dark style self._initialize_dark_look_and_feel() # try to set the font size the same as Blender text_size = 9 if len(bpy.context.preferences.ui_styles) > 0: self.log_debug( "Applying Blender settings to QApplication style...") text_size = (bpy.context.preferences.ui_styles[0].widget.points - 2 ) # MAGIC NUMBER TOTALLY CHOSEN BY EYE ui_scale = bpy.context.preferences.system.ui_scale text_size *= ui_scale self._qt_app.setStyleSheet(f""".QMenu {{ font-size: {text_size}pt; }} .QWidget {{ font-size: {text_size}pt; }}""") self.logger.debug("QT Application: %s" % self._qt_app_main_window)
def test_get_shotgun_storage_key(self): """ Tests get_shotgun_storage_key """ gssk = ShotgunPath.get_shotgun_storage_key self.assertEqual(gssk("win32"), "windows_path") self.assertEqual(gssk("linux2"), "linux_path") self.assertEqual(gssk("linux"), "linux_path") self.assertEqual(gssk("linux3"), "linux_path") self.assertEqual(gssk("darwin"), "mac_path") if is_windows(): self.assertEqual(gssk(), "windows_path") if is_macos(): self.assertEqual(gssk(), "mac_path") if is_linux(): self.assertEqual(gssk(), "linux_path")
def _get_current_os_user(): """ Gets the current operating system username. :returns: The username string. """ if is_windows(): # http://stackoverflow.com/questions/117014/how-to-retrieve-name-of-current-windows-user-ad-or-local-using-python return os.environ.get("USERNAME", None) else: try: import pwd pwd_entry = pwd.getpwuid(os.geteuid()) return pwd_entry[0] except: return None
def test_global(self): """ tests the global root """ pref_path = LocalFileStorageManager.get_global_root( LocalFileStorageManager.PREFERENCES ) cache_path = LocalFileStorageManager.get_global_root( LocalFileStorageManager.CACHE ) persistent_path = LocalFileStorageManager.get_global_root( LocalFileStorageManager.PERSISTENT ) log_path = LocalFileStorageManager.get_global_root( LocalFileStorageManager.LOGGING ) if is_macos(): self.assertEqual(cache_path, os.path.expanduser("~/Library/Caches/Shotgun")) self.assertEqual( pref_path, os.path.expanduser("~/Library/Preferences/Shotgun") ) self.assertEqual( persistent_path, os.path.expanduser("~/Library/Application Support/Shotgun"), ) self.assertEqual(log_path, os.path.expanduser("~/Library/Logs/Shotgun")) elif is_windows(): app_data = os.environ.get("APPDATA", "APPDATA_NOT_SET") self.assertEqual(cache_path, os.path.join(app_data, "Shotgun")) self.assertEqual( pref_path, os.path.join(app_data, "Shotgun", "Preferences") ) self.assertEqual(persistent_path, os.path.join(app_data, "Shotgun", "Data")) self.assertEqual(log_path, os.path.join(app_data, "Shotgun", "Logs")) else: # linux self.assertEqual(cache_path, os.path.expanduser("~/.shotgun")) self.assertEqual(pref_path, os.path.expanduser("~/.shotgun/preferences")) self.assertEqual(persistent_path, os.path.expanduser("~/.shotgun/data")) self.assertEqual(log_path, os.path.expanduser("~/.shotgun/logs"))
def test_get_publish_path_local_file_link(self): """ Tests the hook.get_publish_path method """ hook = sgtk.Hook(parent=self.tk) sg_dict = { "id": 123, "type": "PublishedFile", "code": "foo", "path": { "content_type": "image/png", "id": 25826, "link_type": "local", "local_path": None, "local_path_linux": "/local/path/to/file.ext", "local_path_mac": "/local/path/to/file.ext", "local_path_windows": r"c:\local\path\to\file.ext", "local_storage": {"id": 39, "name": "home", "type": "LocalStorage"}, "name": "foo.png", "type": "Attachment", "url": "file:///local/path/to/file.ext", }, } # get the current os platform local_path = { "win32": sg_dict["path"]["local_path_windows"], "linux2": sg_dict["path"]["local_path_linux"], "darwin": sg_dict["path"]["local_path_mac"], }[sgsix.platform] sg_dict["path"]["local_path"] = local_path if is_windows(): expected_path = r"c:\local\path\to\file.ext" else: expected_path = "/local/path/to/file.ext" self.assertEqual(hook.get_publish_path(sg_dict), expected_path) self.assertEqual( hook.get_publish_paths([sg_dict, sg_dict]), [expected_path, expected_path] )
def setUp(self): super(TestBackups, self).setUp() pathHead, pathTail = os.path.split(__file__) self._core_repo_path = os.path.join(pathHead, "..", "..") self._temp_test_path = os.path.join(pathHead, "..", "fixtures", "bootstrap_tests", "test_backups") if ( is_windows() ): # On Windows, filenames in temp path are too long for straight copy ... core_copy_path = os.path.join(self.tank_temp, "tk-core-copy") if not os.path.exists(core_copy_path): # ... so avoid copying ignore folders to avoid errors when copying the core repo copytree( self._core_repo_path, core_copy_path, ignore=ignore_patterns("tests", "docs", "coverage_html_report"), ) self._core_repo_path = core_copy_path
def test_with_mixed_slashes(self): """ Check that a sgtk init works for this path """ # only run this test on windows if is_windows(): self.sg_pc_entity[ "windows_path"] = self.pipeline_config_root.replace("\\", "/") self.add_to_sg_mock_db(self.sg_pc_entity) self.add_to_sg_mock_db(self.project) self.add_to_sg_mock_db({ "type": "Shot", "id": 1, "project": self.project }) os.environ["TANK_CURRENT_PC"] = self.pipeline_config_root try: sgtk.sgtk_from_entity("Shot", 1) finally: del os.environ["TANK_CURRENT_PC"]
def test_windows_unc_path(self): """ Tests resolving a windows unc path style file://path url """ sg_dict = { "id": 123, "type": "PublishedFile", "code": "foo", "path": { "url": "file://share/foo/bar/baz", "type": "Attachment", "name": "bar.baz", "link_type": "web", "content_type": None, }, } local_path = sgtk.util.resolve_publish_path(self.tk, sg_dict) if is_windows(): self.assertEqual(r"\\share\foo\bar\baz", local_path) else: self.assertEqual("//share/foo/bar/baz", local_path)
def test_windows_drive_path(self): """ Tests resolving a windows file://path url with a drive letter """ sg_dict = { "id": 123, "type": "PublishedFile", "code": "foo", "path": { "url": "file:///C:/foo/bar/baz", "type": "Attachment", "name": "bar.baz", "link_type": "web", "content_type": None, }, } local_path = sgtk.util.resolve_publish_path(self.tk, sg_dict) if is_windows(): self.assertEqual(r"C:\foo\bar\baz", local_path) else: self.assertEqual("C:/foo/bar/baz", local_path)
def test_nix_path(self): """ Tests resolving a unix/macosx file://path url """ sg_dict = { "id": 123, "type": "PublishedFile", "code": "foo", "path": { "url": "file:///foo%20/bar.baz", "type": "Attachment", "name": "bar.baz", "link_type": "web", "content_type": None, }, } local_path = sgtk.util.resolve_publish_path(self.tk, sg_dict) if is_windows(): self.assertEqual(r"\foo \bar.baz", local_path) else: self.assertEqual("/foo /bar.baz", local_path)
def test_paths(self): """Test paths match those in roots for current os.""" root_file = open(self.root_file_path, "w") root_file.write(yaml.dump(self.roots)) root_file.close() pc = tank.pipelineconfig_factory.from_path(self.project_root) result = pc.get_data_roots() # Determine platform if is_macos(): platform = "mac_path" elif is_linux(): platform = "linux_path" elif is_windows(): platform = "windows_path" project_name = os.path.basename(self.project_root) for root_name, root_path in result.items(): expected_path = os.path.join(self.roots[root_name][platform], project_name) self.assertEqual(expected_path, root_path)