# Path: ddsc/core/fileuploader.py
# class ForbiddenSendExternalException(Exception):
# class FileUploader(object):
# class ParentData(object):
# class FileUploadOperations(object):
# class ParallelChunkProcessor(object):
# class ChunkSender(object):
#     def __init__(self, config, data_service, local_file, hash_data, watcher, file_upload_post_processor=None):
#     def upload(self, project_id, parent_kind, parent_id):
#     def __init__(self, parent_kind, parent_id):
#     def __init__(self, data_service, waiting_monitor):
#     def _create_upload(self, project_id, path_data, hash_data, remote_filename=None, storage_provider_id=None,
#                        chunked=True):
#         def func():
#     def create_upload(self, project_id, path_data, hash_data, remote_filename=None, storage_provider_id=None):
#     def create_upload_and_chunk_url(self, project_id, path_data, hash_data, remote_filename=None,
#                                     storage_provider_id=None):
#     def create_file_chunk_url(self, upload_id, chunk_num, chunk):
#         def func():
#     def send_file_external(self, url_json, chunk):
#     def _send_file_external_with_retry(self, http_verb, host, url, http_headers, chunk):
#     def _show_retry_warning(host):
#     def finish_upload(self, upload_id, hash_data, parent_data, remote_file_id):
#     def _verify_upload_response(upload_response):
#     def __init__(self, file_uploader):
#     def run(self):
#     def determine_num_chunks(chunk_size, file_size):
#     def make_work_parcels(upload_workers, num_chunks):
#     def divide_work(list_of_indexes, batch_size):
#     def make_and_start_process(self, index, num_items, progress_queue):
# def upload_async(data_service_auth_data, config, upload_id,
#                  filename, index, num_chunks_to_send, progress_queue):
#     def __init__(self, data_service, upload_id, filename, chunk_size, index, num_chunks_to_send, progress_queue):
#     def send(self):
#     def _send_chunk(self, chunk, chunk_num):
# 
# Path: ddsc/core/ddsapi.py
# class DSResourceNotConsistentError(DataServiceError):
#     """
#     Exception thrown when a DukeDS resource is not in a consistent state.
#     The resource may become consistent at some future point in time so users can retry.
#     """
#     def __init__(self, response, url_suffix, request_data):
#         super(self.__class__, self).__init__(response, url_suffix, request_data)
# 
# class DataServiceError(Exception):
#     """
#     Error that wraps up info about it and creates an informative string.
#     """
#     def __init__(self, response, url_suffix, request_data):
#         """
#         Create exception for failed response.
#         :param response: requests.Response response that was in error
#         :param url_suffix: str url we were trying to connect to
#         :param request_data: object data we were sending to url
#         """
#         resp_json = None
#         try:
#             resp_json = response.json()
#         except:
#             resp_json = {}
#         if response.status_code == 500:
#             if resp_json and not resp_json.get('reason'):
#                 resp_json = {'reason': 'Internal Server Error', 'suggestion': 'Contact DDS support.'}
#         Exception.__init__(self, 'Error {} on {}\nReason:{}\nSuggestion:{}'.format(
#             response.status_code, url_suffix, resp_json.get('reason', resp_json.get('error', '')),
#             resp_json.get('suggestion', '')
#         ))
#         self.response = resp_json
#         self.url_suffix = url_suffix
#         self.request_data = request_data
#         self.status_code = response.status_code
# 
# Path: ddsc/exceptions.py
# class DDSUserException(Exception):
#     """
#     Exception with an error message to be displayed to the user on the command line.
#     """
#     pass


from unittest import TestCase
from ddsc.core.fileuploader import ParallelChunkProcessor, upload_async, FileUploadOperations, \
    RetrySettings, ForbiddenSendExternalException, ChunkSender, FileUploader
from ddsc.core.ddsapi import DSResourceNotConsistentError, DataServiceError
from ddsc.exceptions import DDSUserException
from mock import MagicMock, Mock, patch, call, ANY
import requests
        self.mimetype = mimetype


class TestParallelChunkProcessor(TestCase):
    def test_determine_num_chunks(self):
        values = [
            # chunk_size, file_size, expected
            (100, 300, 3),
            (100, 101, 2),
            (100, 199, 2),
            (5, 7, 2),
            (100, 900000, 9000),
            (125, 123, 1),
            (122, 123, 2),
            (100, 0, 1)
        ]
        for chunk_size, file_size, expected in values:
            num_chunks = ParallelChunkProcessor.determine_num_chunks(chunk_size, file_size)
            self.assertEqual(expected, num_chunks)

    def test_make_work_parcels(self):
        values = [
            # upload_workers, num_chunks, expected
            (4, 4, [(0, 1), (1, 1), (2, 1), (3, 1)]),
            (4, 19, [(0, 5), (5, 5), (10, 5), (15, 4)]),
            (5, 31, [(0, 7), (7, 7), (14, 7), (21, 7), (28, 3)]),
            (5, 4, [(0, 1), (1, 1), (2, 1), (3, 1)]),
            (1, 4, [(0, 4)]),
        ]
        for upload_workers, num_chunks, expected in values:

# Path: ddsc/core/fileuploader.py
# class ForbiddenSendExternalException(Exception):
# class FileUploader(object):
# class ParentData(object):
# class FileUploadOperations(object):
# class ParallelChunkProcessor(object):
# class ChunkSender(object):
#     def __init__(self, config, data_service, local_file, hash_data, watcher, file_upload_post_processor=None):
#     def upload(self, project_id, parent_kind, parent_id):
#     def __init__(self, parent_kind, parent_id):
#     def __init__(self, data_service, waiting_monitor):
#     def _create_upload(self, project_id, path_data, hash_data, remote_filename=None, storage_provider_id=None,
#                        chunked=True):
#         def func():
#     def create_upload(self, project_id, path_data, hash_data, remote_filename=None, storage_provider_id=None):
#     def create_upload_and_chunk_url(self, project_id, path_data, hash_data, remote_filename=None,
#                                     storage_provider_id=None):
#     def create_file_chunk_url(self, upload_id, chunk_num, chunk):
#         def func():
#     def send_file_external(self, url_json, chunk):
#     def _send_file_external_with_retry(self, http_verb, host, url, http_headers, chunk):
#     def _show_retry_warning(host):
#     def finish_upload(self, upload_id, hash_data, parent_data, remote_file_id):
#     def _verify_upload_response(upload_response):
#     def __init__(self, file_uploader):
#     def run(self):
#     def determine_num_chunks(chunk_size, file_size):
#     def make_work_parcels(upload_workers, num_chunks):
#     def divide_work(list_of_indexes, batch_size):
#     def make_and_start_process(self, index, num_items, progress_queue):
# def upload_async(data_service_auth_data, config, upload_id,
#                  filename, index, num_chunks_to_send, progress_queue):
#     def __init__(self, data_service, upload_id, filename, chunk_size, index, num_chunks_to_send, progress_queue):
#     def send(self):
#     def _send_chunk(self, chunk, chunk_num):
# 
# Path: ddsc/core/ddsapi.py
# class DSResourceNotConsistentError(DataServiceError):
#     """
#     Exception thrown when a DukeDS resource is not in a consistent state.
#     The resource may become consistent at some future point in time so users can retry.
#     """
#     def __init__(self, response, url_suffix, request_data):
#         super(self.__class__, self).__init__(response, url_suffix, request_data)
# 
# class DataServiceError(Exception):
#     """
#     Error that wraps up info about it and creates an informative string.
#     """
#     def __init__(self, response, url_suffix, request_data):
#         """
#         Create exception for failed response.
#         :param response: requests.Response response that was in error
#         :param url_suffix: str url we were trying to connect to
#         :param request_data: object data we were sending to url
#         """
#         resp_json = None
#         try:
#             resp_json = response.json()
#         except:
#             resp_json = {}
#         if response.status_code == 500:
#             if resp_json and not resp_json.get('reason'):
#                 resp_json = {'reason': 'Internal Server Error', 'suggestion': 'Contact DDS support.'}
#         Exception.__init__(self, 'Error {} on {}\nReason:{}\nSuggestion:{}'.format(
#             response.status_code, url_suffix, resp_json.get('reason', resp_json.get('error', '')),
#             resp_json.get('suggestion', '')
#         ))
#         self.response = resp_json
#         self.url_suffix = url_suffix
#         self.request_data = request_data
#         self.status_code = response.status_code
# 
# Path: ddsc/exceptions.py
# class DDSUserException(Exception):
#     """
#     Exception with an error message to be displayed to the user on the command line.
#     """
#     pass


# Path: ddsc/core/tests/test_fileuploader.py
from unittest import TestCase
from ddsc.core.fileuploader import ParallelChunkProcessor, upload_async, FileUploadOperations, \
    RetrySettings, ForbiddenSendExternalException, ChunkSender, FileUploader
from ddsc.core.ddsapi import DSResourceNotConsistentError, DataServiceError
from ddsc.exceptions import DDSUserException
from mock import MagicMock, Mock, patch, call, ANY
import requests

        self.mimetype = mimetype


class TestParallelChunkProcessor(TestCase):
    def test_determine_num_chunks(self):
        values = [
            # chunk_size, file_size, expected
            (100, 300, 3),
            (100, 101, 2),
            (100, 199, 2),
            (5, 7, 2),
            (100, 900000, 9000),
            (125, 123, 1),
            (122, 123, 2),
            (100, 0, 1)
        ]
        for chunk_size, file_size, expected in values:
            num_chunks = ParallelChunkProcessor.determine_num_chunks(chunk_size, file_size)
            self.assertEqual(expected, num_chunks)

    def test_make_work_parcels(self):
        values = [
            # upload_workers, num_chunks, expected
            (4, 4, [(0, 1), (1, 1), (2, 1), (3, 1)]),
            (4, 19, [(0, 5), (5, 5), (10, 5), (15, 4)]),
            (5, 31, [(0, 7), (7, 7), (14, 7), (21, 7), (28, 3)]),
            (5, 4, [(0, 1), (1, 1), (2, 1), (3, 1)]),
            (1, 4, [(0, 4)]),
        ]
        for upload_workers, num_chunks, expected in values:

            result = ParallelChunkProcessor.make_work_parcels(upload_workers, num_chunks)