function dry_run_test
Performs a dry run test of SharePoint to FileCloud synchronization, analyzing up to a specified number of documents without actually transferring files.
/tf/active/vicechatdev/SPFCsync/dry_run_test.py
40 - 265
complex
Purpose
This function simulates a file synchronization operation between SharePoint and FileCloud to preview what actions would be taken (new uploads, updates, or skips) without modifying any files. It connects to both services, retrieves documents from SharePoint, compares them with FileCloud versions, and provides a detailed report of planned actions. This is useful for validating sync logic, troubleshooting path mappings, and understanding what changes would occur before running an actual sync.
Source Code
def dry_run_test(max_documents=100):
"""
Perform a dry run test with limited documents
"""
print("๐งช SharePoint to FileCloud Sync - Dry Run Test")
print("=" * 60)
# Initialize clients
config = Config()
print("๐ Connecting to SharePoint...")
sp_client = SharePointGraphClient(
site_url=config.SHAREPOINT_SITE_URL,
client_id=config.AZURE_CLIENT_ID,
client_secret=config.AZURE_CLIENT_SECRET
)
print("๐ Connecting to FileCloud...")
fc_client = FileCloudClient(
server_url=config.FILECLOUD_SERVER_URL,
username=config.FILECLOUD_USERNAME,
password=config.FILECLOUD_PASSWORD
)
# Test connections
try:
# SharePoint connection is tested during initialization
print("โ
SharePoint connection successful")
except Exception as e:
print(f"โ SharePoint connection failed: {e}")
return
try:
# FileCloud connection is tested during initialization
print("โ
FileCloud connection successful")
except Exception as e:
print(f"โ FileCloud connection failed: {e}")
return
print(f"\n๐ Discovering up to {max_documents} documents from SharePoint...")
# Get limited documents from SharePoint
documents = []
try:
# Start with root folder and collect documents up to the limit
sp_client._get_documents_recursive("/", documents, max_files=max_documents)
if not documents:
print("โ No documents found in SharePoint")
return
print(f"โ
Found {len(documents)} documents in SharePoint")
except Exception as e:
print(f"โ Error retrieving SharePoint documents: {e}")
return
print(f"\n๐ Analyzing sync requirements...")
print(f"๐ FileCloud base path: {config.FILECLOUD_BASE_PATH}")
print(f"๐ FileCloud server: {config.FILECLOUD_SERVER_URL}")
print("-" * 60)
actions = {
'upload_new': [],
'update_existing': [],
'skip_same': [],
'errors': []
}
for i, doc in enumerate(documents, 1):
print(f"\n[{i}/{len(documents)}] Analyzing: {doc['name']}")
print(f" ๐ Path: {doc['folder_path']}")
print(f" ๐ Size: {format_file_size(doc.get('size'))}")
print(f" ๐
Modified: {format_datetime(doc.get('modified'))}")
try:
# Construct FileCloud path - let's trace this step by step
print(f" ๐ง Building FileCloud path:")
print(f" SharePoint folder_path: '{doc['folder_path']}'")
print(f" SharePoint file name: '{doc['name']}'")
# Start with the configured base path
base_path = config.FILECLOUD_BASE_PATH
print(f" FileCloud base path: '{base_path}'")
# Add the SharePoint folder structure
sp_folder = doc['folder_path']
if sp_folder and sp_folder != '/':
if not base_path.endswith('/'):
base_path += '/'
if sp_folder.startswith('/'):
sp_folder = sp_folder[1:] # Remove leading slash
fc_path = base_path + sp_folder + '/' + doc['name']
else:
# File is in root
if not base_path.endswith('/'):
base_path += '/'
fc_path = base_path + doc['name']
print(f" Final FileCloud path: '{fc_path}'")
print(f" ๐ Looking for file in FileCloud at: {fc_path}")
# Check if file exists in FileCloud
print(f" ๐ก Calling FileCloud get_file_info with path: '{fc_path}'")
fc_info = fc_client.get_file_info(fc_path)
if fc_info is None:
print(f" ๐ File not found in FileCloud (will be uploaded as new)")
# Let's also try to check if the folder exists
folder_path = '/'.join(fc_path.split('/')[:-1])
print(f" ๏ฟฝ๏ธ Checking if folder exists: '{folder_path}'")
try:
folder_info = fc_client.get_file_info(folder_path)
if folder_info:
print(f" โ
Parent folder exists in FileCloud")
else:
print(f" ๐ Parent folder does not exist (will be created)")
except Exception as e:
print(f" โ Could not check parent folder: {e}")
else:
print(f" ๏ฟฝ๐ File found in FileCloud:")
print(f" Size: {format_file_size(fc_info.get('size'))}")
print(f" Modified: {format_datetime(fc_info.get('lastmodified'))}")
print(f" FileCloud info: {fc_info}")
if fc_info is None:
# File doesn't exist - would upload as new
actions['upload_new'].append({
'document': doc,
'fc_path': fc_path,
'action': 'Upload as new file'
})
print(f" โ Action: UPLOAD NEW FILE")
else:
# File exists - compare modification times
# Compare modification times to decide on action
sp_modified = doc.get('modified')
fc_modified = fc_info.get('lastmodified')
if sp_modified and fc_modified:
try:
sp_dt = datetime.fromisoformat(sp_modified.replace('Z', '+00:00'))
fc_dt = datetime.fromisoformat(fc_modified.replace('Z', '+00:00'))
if sp_dt > fc_dt:
actions['update_existing'].append({
'document': doc,
'fc_path': fc_path,
'fc_info': fc_info,
'action': 'Update existing file (SharePoint newer)'
})
print(f" ๐ Action: UPDATE EXISTING (SP newer: {format_datetime(sp_modified)} vs FC: {format_datetime(fc_modified)})")
else:
actions['skip_same'].append({
'document': doc,
'fc_path': fc_path,
'fc_info': fc_info,
'action': 'Skip - FileCloud is up to date'
})
print(f" โญ๏ธ Action: SKIP (FC up to date: {format_datetime(fc_modified)} vs SP: {format_datetime(sp_modified)})")
except Exception as e:
actions['errors'].append({
'document': doc,
'fc_path': fc_path,
'error': f"Date comparison error: {e}"
})
print(f" โ Action: ERROR comparing dates: {e}")
else:
# Can't compare dates - assume update needed
actions['update_existing'].append({
'document': doc,
'fc_path': fc_path,
'fc_info': fc_info,
'action': 'Update existing file (cannot compare dates)'
})
print(f" ๐ Action: UPDATE EXISTING (cannot compare dates)")
except Exception as e:
actions['errors'].append({
'document': doc,
'fc_path': fc_path if 'fc_path' in locals() else 'Unknown',
'error': str(e)
})
print(f" โ Action: ERROR: {e}")
# Print summary
print("\n" + "=" * 60)
print("๐ DRY RUN SUMMARY")
print("=" * 60)
print(f"๐ Total documents analyzed: {len(documents)}")
print(f"โ New files to upload: {len(actions['upload_new'])}")
print(f"๐ Existing files to update: {len(actions['update_existing'])}")
print(f"โญ๏ธ Files to skip (up to date): {len(actions['skip_same'])}")
print(f"โ Errors encountered: {len(actions['errors'])}")
# Show details for each category
if actions['upload_new']:
print(f"\nโ NEW FILES TO UPLOAD ({len(actions['upload_new'])}):")
for item in actions['upload_new'][:10]: # Show first 10
doc = item['document']
print(f" โข {doc['name']} โ {item['fc_path']}")
print(f" Size: {format_file_size(doc.get('size'))}")
if len(actions['upload_new']) > 10:
print(f" ... and {len(actions['upload_new']) - 10} more")
if actions['update_existing']:
print(f"\n๐ FILES TO UPDATE ({len(actions['update_existing'])}):")
for item in actions['update_existing'][:10]: # Show first 10
doc = item['document']
print(f" โข {doc['name']} โ {item['fc_path']}")
print(f" Size: {format_file_size(doc.get('size'))}")
if len(actions['update_existing']) > 10:
print(f" ... and {len(actions['update_existing']) - 10} more")
if actions['errors']:
print(f"\nโ ERRORS ({len(actions['errors'])}):")
for item in actions['errors'][:5]: # Show first 5 errors
doc = item['document']
print(f" โข {doc['name']}: {item['error']}")
if len(actions['errors']) > 5:
print(f" ... and {len(actions['errors']) - 5} more errors")
print(f"\n๐ก This was a DRY RUN - no files were actually uploaded or modified")
print(f"๐ To perform the actual sync, run: python main.py --once")
Parameters
| Name | Type | Default | Kind |
|---|---|---|---|
max_documents |
- | 100 | positional_or_keyword |
Parameter Details
max_documents: Maximum number of documents to retrieve from SharePoint for analysis. Defaults to 100. This limit helps prevent overwhelming API calls and provides a manageable sample size for testing. Must be a positive integer.
Return Value
This function does not return any value (implicitly returns None). Instead, it prints comprehensive output to the console including connection status, document analysis details, and a summary report of planned actions categorized as: new uploads, updates, skips, and errors.
Dependencies
datetimeossys
Required Imports
import os
import sys
from datetime import datetime
from sharepoint_graph_client import SharePointGraphClient
from filecloud_client import FileCloudClient
from config import Config
Usage Example
# Basic usage with default 100 documents
dry_run_test()
# Test with a smaller sample size
dry_run_test(max_documents=25)
# Test with a larger sample
dry_run_test(max_documents=500)
# Example output interpretation:
# โ
SharePoint connection successful
# โ
FileCloud connection successful
# ๐ Total documents analyzed: 100
# โ New files to upload: 45
# ๐ Existing files to update: 30
# โญ๏ธ Files to skip (up to date): 20
# โ Errors encountered: 5
Best Practices
- Always run this dry run test before executing actual file synchronization to preview changes
- Start with a small max_documents value (e.g., 10-25) when first testing to quickly identify configuration issues
- Review the error section carefully to identify path mapping or permission issues before running actual sync
- Verify that the FileCloud base path is correctly configured by examining the path construction output
- Check that date comparisons are working correctly to avoid unnecessary file updates
- Ensure both SharePoint and FileCloud credentials are valid before running
- Monitor the console output for path construction details to troubleshoot folder structure issues
- Use this function to validate that the _get_documents_recursive method respects the max_files limit
- Pay attention to files that would be updated vs skipped to understand sync behavior
- If many errors occur, reduce max_documents to isolate problematic files more easily
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
function main_v17 71.9% similar
-
function test_filecloud_integration 69.6% similar
-
function main_v16 68.3% similar
-
class SyncDiagnostics 67.7% similar
-
function main_v37 66.5% similar