text:
"""
Tests For Scheduler
"""

import collections
from datetime import datetime
import ddt
import mock
from oslo_config import cfg

from cinder.common import constants
from cinder import context
from cinder import exception
from cinder.message import message_field
from cinder import objects
from cinder.scheduler import driver
from cinder.scheduler import manager
from cinder import test
from cinder.tests.unit import fake_constants as fake
from cinder.tests.unit import fake_volume
from cinder.tests.unit.scheduler import fakes as fake_scheduler
from cinder.tests.unit import utils as tests_utils

CONF = cfg.CONF

@ddt.ddt
class SchedulerManagerTestCase(test.TestCase):
    """Test case for scheduler manager."""

    manager_cls = manager.SchedulerManager
    driver_cls = driver.Scheduler
    driver_cls_name = 'cinder.scheduler.driver.Scheduler'

    class AnException(Exception):
        pass

    def setUp(self):
        super(SchedulerManagerTestCase, self).setUp()
        self.flags(scheduler_driver=self.driver_cls_name)
        self.manager = self.manager_cls()
        self.manager._startup_delay = False
        self.context = context.get_admin_context()
        self.topic = 'fake_topic'
        self.fake_args = (1, 2, 3)
        self.fake_kwargs = {'cat': 'meow', 'dog': 'woof'}

    def test_1_correct_init(self):
        # Correct scheduler driver
        manager = self.manager
        self.assertIsInstance(manager.driver, self.driver_cls)

    @mock.patch('eventlet.sleep')
    @mock.patch('cinder.volume.rpcapi.VolumeAPI.publish_service_capabilities')
    def test_init_host_with_rpc(self, publish_capabilities_mock, sleep_mock):
        self.manager._startup_delay = True
        self.manager.init_host_with_rpc()
        publish_capabilities_mock.assert_called_once_with(mock.ANY)
        sleep_mock.assert_called_once_with(CONF.periodic_interval)
        self.assertFalse(self.manager._startup_delay)

    @mock.patch('cinder.scheduler.driver.Scheduler.backend_passes_filters')
    @mock.patch(
        'cinder.scheduler.host_manager.BackendState.consume_from_volume')
    @mock.patch('cinder.volume.rpcapi.VolumeAPI.manage_existing_snapshot')
    def test_manage_existing_snapshot(self, mock_manage_existing_snapshot,
                                      mock_consume, mock_backend_passes):
        volume = fake_volume.fake_volume_obj(self.context, **{'size': 1})
        fake_backend = fake_scheduler.FakeBackendState('host1', {})
        mock_backend_passes.return_value = fake_backend

        self.manager.manage_existing_snapshot(self.context, volume,
                                              'fake_snapshot', 'fake_ref',
                                              None)

        mock_consume.assert_called_once_with({'size': 1})
        mock_manage_existing_snapshot.assert_called_once_with(
            self.context, 'fake_snapshot', 'fake_ref',
            volume.service_topic_queue)

    @mock.patch('cinder.objects.service.Service.get_minimum_rpc_version')
    @mock.patch('cinder.objects.service.Service.get_minimum_obj_version')
    @mock.patch('cinder.rpc.LAST_RPC_VERSIONS', {'cinder-volume': '1.3'})
    @mock.patch('cinder.rpc.LAST_OBJ_VERSIONS', {'cinder-volume': '1.4',
                                                 'cinder-scheduler': '1.4'})
    def test_reset(self, get_min_obj, get_min_rpc):
        mgr = self.manager_cls()

        volume_rpcapi = mgr.driver.volume_rpcapi
        self.assertEqual('1.3', volume_rpcapi.client.version_cap)
        self.assertEqual('1.4',
                         volume_rpcapi.client.serializer._base.version_cap)
        get_min_obj.return_value = objects.base.OBJ_VERSIONS.get_current()
        mgr.reset()

        volume_rpcapi = mgr.driver.volume_rpcapi
        self.assertEqual(get_min_rpc.return_value,
                         volume_rpcapi.client.version_cap)
        self.assertEqual(get_min_obj.return_value,
                         volume_rpcapi.client.serializer._base.version_cap)
        self.assertIsNone(volume_rpcapi.client.serializer._base.manifest)

    @mock.patch('cinder.message.api.API.cleanup_expired_messages')
    def test_clean_expired_messages(self, mock_clean):

        self.manager._clean_expired_messages(self.context)

        mock_clean.assert_called_once_with(self.context)

    @mock.patch('cinder.scheduler.driver.Scheduler.backend_passes_filters')
    @mock.patch(
        'cinder.scheduler.host_manager.BackendState.consume_from_volume')
    @mock.patch('cinder.volume.rpcapi.VolumeAPI.extend_volume')
    def test_extend_volume(self, mock_extend,
                           mock_consume, mock_backend_passes):
        volume = fake_volume.fake_volume_obj(self.context, **{'size': 1})
        fake_backend = fake_scheduler.FakeBackendState('host1', {})
        mock_backend_passes.return_value = fake_backend

        self.manager.extend_volume(self.context, volume, 2, 'fake_reservation')

        mock_consume.assert_called_once_with({'size': 1})
        mock_extend.assert_called_once_with(
            self.context, volume, 2, 'fake_reservation')

    @ddt.data('available', 'in-use')
    @mock.patch('cinder.scheduler.driver.Scheduler.backend_passes_filters')
    @mock.patch(
        'cinder.scheduler.host_manager.BackendState.consume_from_volume')
    @mock.patch('cinder.volume.rpcapi.VolumeAPI.extend_volume')
    @mock.patch('cinder.quota.QUOTAS.rollback')
    def test_extend_volume_no_valid_host(self, status, mock_rollback,
                                         mock_extend, mock_consume,
                                         mock_backend_passes):
        volume = fake_volume.fake_volume_obj(self.context,
                                             **{'size': 1,
                                                'previous_status': status})
        no_valid_backend = exception.NoValidBackend(reason='')
        mock_backend_passes.side_effect = [no_valid_backend]

        with mock.patch.object(self.manager,
                               '_set_volume_state_and_notify') as mock_notify:
            self.manager.extend_volume(self.context, volume, 2,
                                       'fake_reservation')
            mock_notify.assert_called_once_with(
                'extend_volume', {'volume_state': {'status': status,
                                                   'previous_status': None}},
                self.context, no_valid_backend, None)
            mock_rollback.assert_called_once_with(
                self.context, 'fake_reservation', project_id=volume.project_id)
            mock_consume.assert_not_called()
            mock_extend.assert_not_called()

    @mock.patch('cinder.quota.QuotaEngine.expire')
    def test_clean_expired_reservation(self, mock_clean):

        self.manager._clean_expired_reservation(self.context)

        mock_clean.assert_called_once_with(self.context)

    @mock.patch('cinder.scheduler.driver.Scheduler.'
                'update_service_capabilities')
    def test_update_service_capabilities_empty_dict(self, _mock_update_cap):
        # Test no capabilities passes empty dictionary
        service = 'fake_service'
        host = 'fake_host'

        self.manager.update_service_capabilities(self.context,
                                                 service_name=service,
                                                 host=host)
        _mock_update_cap.assert_called_once_with(service, host, {}, None, None)

    @mock.patch('cinder.scheduler.driver.Scheduler.'
                'update_service_capabilities')
    def test_update_service_capabilities_correct(self, _mock_update_cap):
        # Test capabilities passes correctly
        service = 'fake_service'
        host = 'fake_host'
        capabilities = {'fake_capability': 'fake_value'}

        self.manager.update_service_capabilities(self.context,
                                                 service_name=service,
                                                 host=host,
                                                 capabilities=capabilities)
        _mock_update_cap.assert_called_once_with(service, host, capabilities,
                                                 None, None)

    @mock.patch('cinder.scheduler.driver.Scheduler.'
                'notify_service_capabilities')
    def test_notify_service_capabilities_no_timestamp(self, _mock_notify_cap):
        """Test old interface that receives host."""
        service = 'volume'
        host = 'fake_host'
        capabilities = {'fake_capability': 'fake_value'}

        self.manager.notify_service_capabilities(self.context,
                                                 service_name=service,
                                                 host=host,
                                                 capabilities=capabilities)
        _mock_notify_cap.assert_called_once_with(service, host, capabilities,
                                                 None)

    @mock.patch('cinder.scheduler.driver.Scheduler.'
                'notify_service_capabilities')
    def test_notify_service_capabilities_timestamp(self, _mock_notify_cap):
        """Test new interface that receives backend and timestamp."""
        service = 'volume'
        backend = 'fake_cluster'
        capabilities = {'fake_capability': 'fake_value'}

        timestamp = '1970-01-01T00:00:00.000000'

        self.manager.notify_service_capabilities(self.context,
                                                 service_name=service,
                                                 backend=backend,
                                                 capabilities=capabilities,
                                                 timestamp=timestamp)
        _mock_notify_cap.assert_called_once_with(service, backend,
                                                 capabilities,
                                                 datetime(1970, 1, 1))

    @mock.patch('cinder.scheduler.driver.Scheduler.schedule_create_volume')
    @mock.patch('cinder.message.api.API.create')
    @mock.patch('cinder.db.volume_update')
    def test_create_volume_exception_puts_volume_in_error_state(
            self, _mock_volume_update, _mock_message_create,
            _mock_sched_create):
        # Test NoValidBackend exception behavior for create_volume.
        # Puts the volume in 'error' state and eats the exception.
        _mock_sched_create.side_effect = exception.NoValidBackend(reason="")
        volume = fake_volume.fake_volume_obj(self.context)
        request_spec = {'volume_id': volume.id,
                        'volume': {'id': volume.id, '_name_id': None,
                                   'metadata': {}, 'admin_metadata': {},
                                   'glance_metadata': {}}}
        request_spec_obj = objects.RequestSpec.from_primitives(request_spec)

        self.manager.create_volume(self.context, volume,
                                   request_spec=request_spec_obj,
                                   filter_properties={})
        _mock_volume_update.assert_called_once_with(self.context,
                                                    volume.id,
                                                    {'status': 'error'})
        _mock_sched_create.assert_called_once_with(self.context,
                                                   request_spec_obj, {})

        _mock_message_create.assert_called_once_with(
            self.context, message_field.Action.SCHEDULE_ALLOCATE_VOLUME,
            resource_uuid=volume.id,
            exception=mock.ANY)

    @mock.patch('cinder.scheduler.driver.Scheduler.schedule_create_volume')
    @mock.patch('eventlet.sleep')
    def test_create_volume_no_delay(self, _mock_sleep, _mock_sched_create):
        volume = fake_volume.fake_volume_obj(self.context)

        request_spec = {'volume_id': volume.id}
        request_spec_obj = objects.RequestSpec.from_primitives(request_spec)

        self.manager.create_volume(self.context, volume,
                                   request_spec=request_spec_obj,
                                   filter_properties={})
        _mock_sched_create.assert_called_once_with(self.context,
                                                   request_spec_obj, {})
        self.assertFalse(_mock_sleep.called)

    @mock.patch('cinder.scheduler.driver.Scheduler.schedule_create_volume')
    @mock.patch('eventlet.sleep')
    def test_create_volume_set_worker(self, _mock_sleep, _mock_sched_create):
        """Make sure that the worker is created when creating a volume."""
        volume = tests_utils.create_volume(self.context, status='creating')

        request_spec = {'volume_id': volume.id}

        self.manager.create_volume(self.context, volume,
                                   request_spec=request_spec,
                                   filter_properties={})
        volume.set_worker.assert_called_once_with()

    @mock.patch('cinder.scheduler.driver.Scheduler.schedule_create_volume')
    @mock.patch('cinder.scheduler.driver.Scheduler.is_ready')
    @mock.patch('eventlet.sleep')
    def test_create_volume_delay_scheduled_after_3_tries(self, _mock_sleep,
                                                         _mock_is_ready,
                                                         _mock_sched_create):
        self.manager._startup_delay = True
        volume = fake_volume.fake_volume_obj(self.context)

        request_spec = {'volume_id': volume.id}
        request_spec_obj = objects.RequestSpec.from_primitives(request_spec)

        _mock_is_ready.side_effect = [False, False, True]

        self.manager.create_volume(self.context, volume,
                                   request_spec=request_spec_obj,
                                   filter_properties={})
        _mock_sched_create.assert_called_once_with(self.context,
                                                   request_spec_obj, {})
        calls = [mock.call(1)] * 2
        _mock_sleep.assert_has_calls(calls)
        self.assertEqual(2, _mock_sleep.call_count)

    @mock.patch('cinder.scheduler.driver.Scheduler.schedule_create_volume')
    @mock.patch('cinder.scheduler.driver.Scheduler.is_ready')
    @mock.patch('eventlet.sleep')
    def test_create_volume_delay_scheduled_in_1_try(self, _mock_sleep,
                                                    _mock_is_ready,
                                                    _mock_sched_create):
        self.manager._startup_delay = True
        volume = fake_volume.fake_volume_obj(self.context)

        request_spec = {'volume_id': volume.id}
        request_spec_obj = objects.RequestSpec.from_primitives(request_spec)

        _mock_is_ready.return_value = True

        self.manager.create_volume(self.context, volume,
                                   request_spec=request_spec_obj,
                                   filter_properties={})
        _mock_sched_create.assert_called_once_with(self.context,
                                                   request_spec_obj, {})
        self.assertFalse(_mock_sleep.called)

    @mock.patch('cinder.db.volume_get')
    @mock.patch('cinder.scheduler.driver.Scheduler.backend_passes_filters')
    @mock.patch('cinder.db.volume_update')
    def test_migrate_volume_exception_returns_volume_state(
            self, _mock_volume_update, _mock_backend_passes,
            _mock_volume_get):
        # Test NoValidBackend exception behavior for migrate_volume_to_host.
        # Puts the volume in 'error_migrating' state and eats the exception.
        fake_updates = {'migration_status': 'error'}
        self._test_migrate_volume_exception_returns_volume_state(
            _mock_volume_update, _mock_backend_passes, _mock_volume_get,
            'available', fake_updates)

    @mock.patch('cinder.db.volume_get')
    @mock.patch('cinder.scheduler.driver.Scheduler.backend_passes_filters')
    @mock.patch('cinder.db.volume_update')
    def test_migrate_volume_exception_returns_volume_state_maintenance(
            self, _mock_volume_update, _mock_backend_passes,
            _mock_volume_get):
        fake_updates = {'status': 'available',
                        'migration_status': 'error'}
        self._test_migrate_volume_exception_returns_volume_state(
            _mock_volume_update, _mock_backend_passes, _mock_volume_get,
            'maintenance', fake_updates)

    def _test_migrate_volume_exception_returns_volume_state(
            self, _mock_volume_update, _mock_backend_passes,
            _mock_volume_get, status, fake_updates):
        volume = tests_utils.create_volume(self.context,
                                           status=status,
                                           previous_status='available')
        fake_volume_id = volume.id
        request_spec = {'volume_id': fake_volume_id}
        _mock_backend_passes.side_effect = exception.NoValidBackend(reason="")
        _mock_volume_get.return_value = volume

        self.manager.migrate_volume_to_host(self.context, volume, 'host', True,
                                            request_spec=request_spec,
                                            filter_properties={})
        _mock_volume_update.assert_called_once_with(self.context,
                                                    fake_volume_id,
                                                    fake_updates)
        _mock_backend_passes.assert_called_once_with(self.context, 'host',
                                                     request_spec, {})

    @mock.patch('cinder.db.volume_update')
    @mock.patch('cinder.db.volume_attachment_get_all_by_volume_id')
    @mock.patch('cinder.quota.QUOTAS.rollback')
    def test_retype_volume_exception_returns_volume_state(
            self, quota_rollback, _mock_vol_attachment_get, _mock_vol_update):
        # Test NoValidBackend exception behavior for retype.
        # Puts the volume in original state and eats the exception.
        volume = tests_utils.create_volume(self.context,
                                           status='retyping',
                                           previous_status='in-use')
        instance_uuid = '12345678-1234-5678-1234-567812345678'
        volume_attach = tests_utils.attach_volume(self.context, volume.id,
                                                  instance_uuid, None,
                                                  '/dev/fake')
        _mock_vol_attachment_get.return_value = [volume_attach]
        reservations = mock.sentinel.reservations
        request_spec = {'volume_id': volume.id, 'volume_type': {'id': 3},
                        'migration_policy': 'on-demand',
                        'quota_reservations': reservations}
        _mock_vol_update.return_value = {'status': 'in-use'}
        _mock_find_retype_backend = mock.Mock(
            side_effect=exception.NoValidBackend(reason=""))
        orig_retype = self.manager.driver.find_retype_backend
        self.manager.driver.find_retype_backend = _mock_find_retype_backend

        self.manager.retype(self.context, volume, request_spec=request_spec,
                            filter_properties={})

        _mock_find_retype_backend.assert_called_once_with(self.context,
                                                          request_spec, {},
                                                          'on-demand')
        quota_rollback.assert_called_once_with(self.context, reservations)
        _mock_vol_update.assert_called_once_with(self.context, volume.id,
                                                 {'status': 'in-use'})
        self.manager.driver.find_retype_host = orig_retype

    def test_do_cleanup(self):
        vol = tests_utils.create_volume(self.context, status='creating')
        self.manager._do_cleanup(self.context, vol)

        vol.refresh()
        self.assertEqual('error', vol.status)

    @mock.patch('cinder.scheduler.rpcapi.SchedulerAPI'
                '.determine_rpc_version_cap', mock.Mock(return_value='2.0'))
    def test_upgrading_cloud(self):
        self.assertTrue(self.manager.upgrading_cloud)

    @mock.patch('cinder.scheduler.rpcapi.SchedulerAPI'
                '.determine_rpc_version_cap')
    def test_upgrading_cloud_not(self, cap_mock):
        cap_mock.return_value = self.manager.RPC_API_VERSION
        self.assertFalse(self.manager.upgrading_cloud)

    def test_cleanup_destination_scheduler(self):
        service = objects.Service(id=1, host='hostname',
                                  binary='cinder-scheduler')
        result = self.manager._cleanup_destination(None, service)
        expected = self.manager.sch_api.do_cleanup, None, service.host
        self.assertEqual(expected, result)

    def test_cleanup_destination_volume(self):
        service = objects.Service(id=1, host='hostname', cluster_name=None,
                                  binary=constants.VOLUME_BINARY)
        result = self.manager._cleanup_destination(None, service)
        expected = self.manager.volume_api.do_cleanup, service, service.host
        self.assertEqual(expected, result)

    def test_cleanup_destination_volume_cluster_cache_hit(self):
        cluster = objects.Cluster(id=1, name='mycluster',
                                  binary=constants.VOLUME_BINARY)
        service = objects.Service(id=2, host='hostname',
                                  cluster_name=cluster.name,
                                  binary=constants.VOLUME_BINARY)
        cluster_cache = {'cinder-volume': {'mycluster': cluster}}
        result = self.manager._cleanup_destination(cluster_cache, service)
        expected = self.manager.volume_api.do_cleanup, cluster, cluster.name
        self.assertEqual(expected, result)

    @mock.patch('cinder.objects.Cluster.get_by_id')
    def test_cleanup_destination_volume_cluster_cache_miss(self, get_mock):
        cluster = objects.Cluster(id=1, name='mycluster',
                                  binary=constants.VOLUME_BINARY)
        service = objects.Service(self.context,
                                  id=2, host='hostname',
                                  cluster_name=cluster.name,
                                  binary=constants.VOLUME_BINARY)
        get_mock.return_value = cluster
        cluster_cache = collections.defaultdict(dict)
        result = self.manager._cleanup_destination(cluster_cache, service)
        expected = self.manager.volume_api.do_cleanup, cluster, cluster.name
        self.assertEqual(expected, result)

    @mock.patch('cinder.scheduler.manager.SchedulerManager.upgrading_cloud')
    def test_work_cleanup_upgrading(self, upgrading_mock):
        cleanup_request = objects.CleanupRequest(host='myhost')
        upgrading_mock.return_value = True
        self.assertRaises(exception.UnavailableDuringUpgrade,
                          self.manager.work_cleanup,
                          self.context,
                          cleanup_request)

    @mock.patch('cinder.objects.Cluster.is_up', True)
    @mock.patch('cinder.objects.Service.is_up', False)
    @mock.patch('cinder.scheduler.rpcapi.SchedulerAPI.do_cleanup')
    @mock.patch('cinder.volume.rpcapi.VolumeAPI.do_cleanup')
    @mock.patch('cinder.objects.ServiceList.get_all')
    def test_work_cleanup(self, get_mock, vol_clean_mock, sch_clean_mock):
        args = dict(service_id=1, cluster_name='cluster_name', host='host',
                    binary=constants.VOLUME_BINARY, is_up=False, disabled=True,
                    resource_id=fake.VOLUME_ID, resource_type='Volume')

        cluster = objects.Cluster(id=1, name=args['cluster_name'],
                                  binary=constants.VOLUME_BINARY)
        services = [objects.Service(self.context,
                                    id=2, host='hostname',
                                    cluster_name=cluster.name,
                                    binary=constants.VOLUME_BINARY,
                                    cluster=cluster),
                    objects.Service(self.context,
                                    id=3, host='hostname',
                                    cluster_name=None,
                                    binary=constants.SCHEDULER_BINARY),
                    objects.Service(self.context,
                                    id=4, host='hostname',
                                    cluster_name=None,
                                    binary=constants.VOLUME_BINARY)]
        get_mock.return_value = services

        cleanup_request = objects.CleanupRequest(self.context, **args)
        res = self.manager.work_cleanup(self.context, cleanup_request)
        self.assertEqual((services[:2], services[2:]), res)
        self.assertEqual(1, vol_clean_mock.call_count)
        self.assertEqual(1, sch_clean_mock.call_count)

class SchedulerTestCase(test.TestCase):
    """Test case for base scheduler driver class."""

    # So we can subclass this test and re-use tests if we need.
    driver_cls = driver.Scheduler

    def setUp(self):
        super(SchedulerTestCase, self).setUp()
        self.driver = self.driver_cls()
        self.context = context.RequestContext(fake.USER_ID, fake.PROJECT_ID)
        self.topic = 'fake_topic'

    @mock.patch('cinder.scheduler.driver.Scheduler.'
                'update_service_capabilities')
    def test_update_service_capabilities(self, _mock_update_cap):
        service_name = 'fake_service'
        host = 'fake_host'
        capabilities = {'fake_capability': 'fake_value'}
        self.driver.update_service_capabilities(service_name, host,
                                                capabilities, None)
        _mock_update_cap.assert_called_once_with(service_name, host,
                                                 capabilities, None)

    @mock.patch('cinder.scheduler.host_manager.HostManager.'
                'has_all_capabilities', return_value=False)
    def test_is_ready(self, _mock_has_caps):
        ready = self.driver.is_ready()
        _mock_has_caps.assert_called_once_with()
        self.assertFalse(ready)

class SchedulerDriverBaseTestCase(SchedulerTestCase):
    """Test schedule driver class.

    Test cases for base scheduler driver class methods
    that will fail if the driver is changed.
    """

    def test_unimplemented_schedule(self):
        fake_args = (1, 2, 3)
        fake_kwargs = {'cat': 'meow'}

        self.assertRaises(NotImplementedError, self.driver.schedule,
                          self.context, self.topic, 'schedule_something',
                          *fake_args, **fake_kwargs)

class SchedulerDriverModuleTestCase(test.TestCase):
    """Test case for scheduler driver module methods."""

    def setUp(self):
        super(SchedulerDriverModuleTestCase, self).setUp()
        self.context = context.RequestContext(fake.USER_ID, fake.PROJECT_ID)

    @mock.patch('cinder.db.volume_update')
    @mock.patch('cinder.objects.volume.Volume.get_by_id')
    def test_volume_host_update_db(self, _mock_volume_get, _mock_vol_update):
        volume = fake_volume.fake_volume_obj(self.context)
        _mock_volume_get.return_value = volume

        driver.volume_update_db(self.context, volume.id, 'fake_host',
                                'fake_cluster')
        scheduled_at = volume.scheduled_at.replace(tzinfo=None)
        _mock_vol_update.assert_called_once_with(
            self.context, volume.id, {'host': 'fake_host',
                                      'cluster_name': 'fake_cluster',
                                      'scheduled_at': scheduled_at})


text:
package com.fasterxml.jackson.datatype.jsr310;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.time.Instant;
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.util.TimeZone;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

import org.junit.Before;
import org.junit.Test;

public class TestOffsetDateTimeSerialization
    extends ModuleTestBase
{
    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ISO_OFFSET_DATE_TIME;

    private static final ZoneId UTC = ZoneId.of("UTC");

    private static final ZoneId Z1 = ZoneId.of("America/Chicago");

    private static final ZoneId Z2 = ZoneId.of("America/Anchorage");

    private static final ZoneId Z3 = ZoneId.of("America/Los_Angeles");

    final static class Wrapper {
        @JsonFormat(
                pattern="yyyy_MM_dd'T'HH:mm:ssZ",
                shape=JsonFormat.Shape.STRING)
        public OffsetDateTime value;

        public Wrapper() { }
        public Wrapper(OffsetDateTime v) { value = v; }
    }

    private ObjectMapper MAPPER;

    @Before
    public void setUp()
    {
        MAPPER = newMapper();
    }

    @Test
    public void testSerializationAsTimestamp01Nanoseconds() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.ofInstant(Instant.ofEpochSecond(0L), Z1);
        String value = MAPPER.writer()
                .with(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                .with(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS)
                .writeValueAsString(date);
        assertEquals("The value is not correct.", "0.0", value);
    }

    @Test
    public void testSerializationAsTimestamp01Milliseconds() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.ofInstant(Instant.ofEpochSecond(0L), Z1);
        String value = MAPPER.writer()
                .with(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                .without(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS)
                .writeValueAsString(date);
        assertEquals("The value is not correct.", "0", value);
    }

    @Test
    public void testSerializationAsTimestamp02Nanoseconds() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.ofInstant(Instant.ofEpochSecond(123456789L, 183917322), Z2);
        String value = MAPPER.writer()
                .with(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                .with(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS)
                .writeValueAsString(date);
        assertEquals("The value is not correct.", "123456789.183917322", value);
    }

    @Test
    public void testSerializationAsTimestamp02Milliseconds() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.ofInstant(Instant.ofEpochSecond(123456789L, 183917322), Z2);
        String value = MAPPER.writer()
                .with(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                .without(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS)
                .writeValueAsString(date);
        assertEquals("The value is not correct.", "123456789183", value);
    }

    @Test
    public void testSerializationAsTimestamp03Nanoseconds() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.now(Z3);
        String value = MAPPER.writer()
                .with(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                .with(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS)
                .writeValueAsString(date);
        assertEquals("The value is not correct.", DecimalUtils.toDecimal(date.toEpochSecond(), date.getNano()), value);
    }

    @Test
    public void testSerializationAsTimestamp03Milliseconds() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.now(Z3);
        String value = MAPPER.writer()
                .with(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                .without(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS)
                .writeValueAsString(date);
        assertEquals("The value is not correct.", Long.toString(date.toInstant().toEpochMilli()), value);
    }

    @Test
    public void testSerializationAsString01() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.ofInstant(Instant.ofEpochSecond(0L), Z1);
        String value = MAPPER.writer()
                .without(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                .writeValueAsString(date);
        assertEquals("The value is not correct.", '"' + FORMATTER.format(date) + '"', value);
    }

    @Test
    public void testSerializationAsString02() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.ofInstant(Instant.ofEpochSecond(123456789L, 183917322), Z2);
        String value = MAPPER.writer()
                .without(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                .writeValueAsString(date);
        assertEquals("The value is not correct.", '"' + FORMATTER.format(date) + '"', value);
    }

    @Test
    public void testSerializationAsString03() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.now(Z3);
        String value = MAPPER.writer()
                .without(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                .writeValueAsString(date);
        assertEquals("The value is not correct.", '"' + FORMATTER.format(date) + '"', value);
    }

    @Test
    public void testSerializationWithTypeInfo01() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.ofInstant(Instant.ofEpochSecond(123456789L, 183917322), Z2);
        String value = newMapper()
                .addMixIn(Temporal.class, MockObjectConfiguration.class)
                .writer()
                .with(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                .with(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS)
                .writeValueAsString(date);
        assertEquals("The value is not correct.",
                "[\"" + OffsetDateTime.class.getName() + "\",123456789.183917322]", value);
    }

    @Test
    public void testSerializationWithTypeInfo02() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.ofInstant(Instant.ofEpochSecond(123456789L, 183917322), Z2);
        String value = newMapper()
                .addMixIn(Temporal.class, MockObjectConfiguration.class)
                .writer()
                .with(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                .without(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS)
                .writeValueAsString(date);
        assertEquals("The value is not correct.",
                "[\"" + OffsetDateTime.class.getName() + "\",123456789183]", value);
    }

    @Test
    public void testSerializationWithTypeInfo03() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.now(Z3);
        ObjectMapper m = newMapper()
                .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        m.addMixIn(Temporal.class, MockObjectConfiguration.class);
        String value = m.writeValueAsString(date);

        assertNotNull("The value should not be null.", value);
        assertEquals("The value is not correct.",
                "[\"" + OffsetDateTime.class.getName() + "\",\"" + FORMATTER.format(date) + "\"]", value);
    }

    @Test
    public void testDeserializationAsFloat01WithoutTimeZone() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.ofInstant(Instant.ofEpochSecond(0L), Z1);
        OffsetDateTime value = MAPPER.readValue("0.000000000", OffsetDateTime.class);

        assertNotNull("The value should not be null.", value);
        assertIsEqual(date, value);
        assertEquals("The time zone is not correct.", ZoneOffset.UTC, value.getOffset());
    }

    @Test
    public void testDeserializationAsFloat01WithTimeZone() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.ofInstant(Instant.ofEpochSecond(0L), Z1);
        ObjectMapper m = newMapper()
            .setTimeZone(TimeZone.getDefault());
        OffsetDateTime value = m.readValue("0.000000000", OffsetDateTime.class);

        assertNotNull("The value should not be null.", value);
        assertIsEqual(date, value);
        assertEquals("The time zone is not correct.", getDefaultOffset(date), value.getOffset());
    }

    @Test
    public void testDeserializationAsFloat02WithoutTimeZone() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.ofInstant(Instant.ofEpochSecond(123456789L, 183917322), Z2);

        OffsetDateTime value = MAPPER.readValue("123456789.183917322", OffsetDateTime.class);

        assertNotNull("The value should not be null.", value);
        assertIsEqual(date, value);
        assertEquals("The time zone is not correct.", ZoneOffset.UTC, value.getOffset());
    }

    @Test
    public void testDeserializationAsFloat02WithTimeZone() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.ofInstant(Instant.ofEpochSecond(123456789L, 183917322), Z2);

        OffsetDateTime value = MAPPER.readerFor(OffsetDateTime.class)
                .with(TimeZone.getDefault())
                .readValue("123456789.183917322");

        assertNotNull("The value should not be null.", value);
        assertIsEqual(date, value);
        assertEquals("The time zone is not correct.", getDefaultOffset(date), value.getOffset());
    }

    @Test
    public void testDeserializationAsFloat03WithoutTimeZone() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.now(Z3);

        OffsetDateTime value = MAPPER.readValue(
                DecimalUtils.toDecimal(date.toEpochSecond(), date.getNano()), OffsetDateTime.class
                );

        assertNotNull("The value should not be null.", value);
        assertIsEqual(date, value);
        assertEquals("The time zone is not correct.", ZoneOffset.UTC, value.getOffset());
    }

    @Test
    public void testDeserializationAsFloat03WithTimeZone() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.now(Z3);

        ObjectMapper m = newMapper()
                .setTimeZone(TimeZone.getDefault());
        OffsetDateTime value = m.readValue(
                DecimalUtils.toDecimal(date.toEpochSecond(), date.getNano()), OffsetDateTime.class
        );

        assertNotNull("The value should not be null.", value);
        assertIsEqual(date, value);
        assertEquals("The time zone is not correct.", getDefaultOffset(date), value.getOffset());
    }

    @Test
    public void testDeserializationAsInt01NanosecondsWithoutTimeZone() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.ofInstant(Instant.ofEpochSecond(0L), Z1);
        ObjectMapper m = newMapper()
                .configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, true);
        OffsetDateTime value = m.readValue("0", OffsetDateTime.class);

        assertNotNull("The value should not be null.", value);
        assertIsEqual(date, value);
        assertEquals("The time zone is not correct.", ZoneOffset.UTC, value.getOffset());
    }

    @Test
    public void testDeserializationAsInt01NanosecondsWithTimeZone() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.ofInstant(Instant.ofEpochSecond(0L), Z1);
        ObjectMapper m = newMapper()
                .configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, true)
                .setTimeZone(TimeZone.getDefault());
        OffsetDateTime value = m.readValue("0", OffsetDateTime.class);

        assertNotNull("The value should not be null.", value);
        assertIsEqual(date, value);
        assertEquals("The time zone is not correct.", getDefaultOffset(date), value.getOffset());
    }

    @Test
    public void testDeserializationAsInt01MillisecondsWithoutTimeZone() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.ofInstant(Instant.ofEpochSecond(0L), Z1);
        ObjectMapper m = newMapper()
                .configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, false);
        OffsetDateTime value = m.readValue("0", OffsetDateTime.class);

        assertNotNull("The value should not be null.", value);
        assertIsEqual(date, value);
        assertEquals("The time zone is not correct.", ZoneOffset.UTC, value.getOffset());
    }

    @Test
    public void testDeserializationAsInt01MillisecondsWithTimeZone() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.ofInstant(Instant.ofEpochSecond(0L), Z1);
        ObjectMapper m = newMapper()
                .configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, false)
                .setTimeZone(TimeZone.getDefault());
        OffsetDateTime value = m.readValue("0", OffsetDateTime.class);

        assertNotNull("The value should not be null.", value);
        assertIsEqual(date, value);
        assertEquals("The time zone is not correct.", getDefaultOffset(date), value.getOffset());
    }

    @Test
    public void testDeserializationAsInt02NanosecondsWithoutTimeZone() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.ofInstant(Instant.ofEpochSecond(123456789L, 0), Z2);

        ObjectMapper m = newMapper()
                .configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, true);
        OffsetDateTime value = m.readValue("123456789", OffsetDateTime.class);

        assertNotNull("The value should not be null.", value);
        assertIsEqual(date, value);
        assertEquals("The time zone is not correct.", ZoneOffset.UTC, value.getOffset());
    }

    @Test
    public void testDeserializationAsInt02NanosecondsWithTimeZone() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.ofInstant(Instant.ofEpochSecond(123456789L, 0), Z2);
        ObjectMapper m = newMapper()
                .configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, true)
                .setTimeZone(TimeZone.getDefault());
        OffsetDateTime value = m.readValue("123456789", OffsetDateTime.class);

        assertNotNull("The value should not be null.", value);
        assertIsEqual(date, value);
        assertEquals("The time zone is not correct.", getDefaultOffset(date), value.getOffset());
    }

    @Test
    public void testDeserializationAsInt02MillisecondsWithoutTimeZone() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.ofInstant(Instant.ofEpochSecond(123456789L, 422000000), Z2);
        ObjectMapper m = newMapper()
                .configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, false);
        OffsetDateTime value = m.readValue("123456789422", OffsetDateTime.class);

        assertNotNull("The value should not be null.", value);
        assertIsEqual(date, value);
        assertEquals("The time zone is not correct.", ZoneOffset.UTC, value.getOffset());
    }

    @Test
    public void testDeserializationAsInt02MillisecondsWithTimeZone() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.ofInstant(Instant.ofEpochSecond(123456789L, 422000000), Z2);
        ObjectMapper m = newMapper()
            .configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, false)
            .setTimeZone(TimeZone.getDefault());
        OffsetDateTime value = m.readValue("123456789422", OffsetDateTime.class);

        assertNotNull("The value should not be null.", value);
        assertIsEqual(date, value);
        assertEquals("The time zone is not correct.", getDefaultOffset(date), value.getOffset());
    }

    @Test
    public void testDeserializationAsInt03NanosecondsWithoutTimeZone() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.now(Z3);
        date = date.minus(date.getNano(), ChronoUnit.NANOS);

        ObjectMapper m = newMapper()
                .configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, true);
        OffsetDateTime value = m.readValue(Long.toString(date.toEpochSecond()), OffsetDateTime.class);

        assertNotNull("The value should not be null.", value);
        assertIsEqual(date, value);
        assertEquals("The time zone is not correct.", ZoneOffset.UTC, value.getOffset());
    }

    @Test
    public void testDeserializationAsInt03NanosecondsWithTimeZone() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.now(Z3);
        date = date.minus(date.getNano(), ChronoUnit.NANOS);

        ObjectMapper m = newMapper()
                .configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, true)
                .setTimeZone(TimeZone.getDefault());
        OffsetDateTime value = m.readValue(Long.toString(date.toEpochSecond()), OffsetDateTime.class);

        assertNotNull("The value should not be null.", value);
        assertIsEqual(date, value);
        assertEquals("The time zone is not correct.", getDefaultOffset(date), value.getOffset());
    }

    @Test
    public void testDeserializationAsInt03MillisecondsWithoutTimeZone() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.now(Z3);
        date = date.minus(date.getNano() - (date.get(ChronoField.MILLI_OF_SECOND) * 1_000_000L), ChronoUnit.NANOS);

        ObjectMapper m = newMapper()
                .configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, false);
        OffsetDateTime value =
                m.readValue(Long.toString(date.toInstant().toEpochMilli()), OffsetDateTime.class);

        assertNotNull("The value should not be null.", value);
        assertIsEqual(date, value);
        assertEquals("The time zone is not correct.", ZoneOffset.UTC, value.getOffset());
    }

    @Test
    public void testDeserializationAsInt03MillisecondsWithTimeZone() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.now(Z3);
        date = date.minus(date.getNano() - (date.get(ChronoField.MILLI_OF_SECOND) * 1_000_000L), ChronoUnit.NANOS);

        ObjectMapper m = newMapper()
                .configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, false)
                .setTimeZone(TimeZone.getDefault());
        OffsetDateTime value =
                m.readValue(Long.toString(date.toInstant().toEpochMilli()), OffsetDateTime.class);

        assertNotNull("The value should not be null.", value);
        assertIsEqual(date, value);
        assertEquals("The time zone is not correct.", getDefaultOffset(date), value.getOffset());
    }

    @Test
    public void testDeserializationAsString01WithoutTimeZone() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.ofInstant(Instant.ofEpochSecond(0L), Z1);

        ObjectMapper m = newMapper()
                .configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, true);
        OffsetDateTime value = m.readValue('"' + FORMATTER.format(date) + '"', OffsetDateTime.class);

        assertNotNull("The value should not be null.", value);
        assertIsEqual(date, value);
        assertEquals("The time zone is not correct.", ZoneOffset.UTC, value.getOffset());
    }

    @Test
    public void testDeserializationAsString01WithTimeZone() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.ofInstant(Instant.ofEpochSecond(0L), Z1);
        ObjectMapper m = newMapper()
            .configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, true)
            .setTimeZone(TimeZone.getDefault());
        OffsetDateTime value = m.readValue('"' + FORMATTER.format(date) + '"', OffsetDateTime.class);

        assertNotNull("The value should not be null.", value);
        assertIsEqual(date, value);
        assertEquals("The time zone is not correct.", getDefaultOffset(date), value.getOffset());
    }

    @Test
    public void testDeserializationAsString01WithTimeZoneTurnedOff() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.ofInstant(Instant.ofEpochSecond(0L), Z1);
        ObjectMapper m = newMapper()
            .configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, false)
            .setTimeZone(TimeZone.getDefault());
        OffsetDateTime value = m.readValue('"' + FORMATTER.format(date) + '"', OffsetDateTime.class);

        assertNotNull("The value should not be null.", value);
        assertIsEqual(date, value);
        assertEquals("The time zone is not correct.", getOffset(value, Z1), value.getOffset());
    }

    @Test
    public void testDeserializationAsString02WithoutTimeZone() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.ofInstant(Instant.ofEpochSecond(123456789L, 183917322), Z2);
        ObjectMapper m = newMapper()
                .configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, true);
        OffsetDateTime value = m.readValue('"' + FORMATTER.format(date) + '"', OffsetDateTime.class);

        assertNotNull("The value should not be null.", value);
        assertIsEqual(date, value);
        assertEquals("The time zone is not correct.", ZoneOffset.UTC, value.getOffset());
    }

    @Test
    public void testDeserializationAsString02WithTimeZone() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.ofInstant(Instant.ofEpochSecond(123456789L, 183917322), Z2);
        ObjectMapper m = newMapper()
            .configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, true)
            .setTimeZone(TimeZone.getDefault());
        OffsetDateTime value = m.readValue('"' + FORMATTER.format(date) + '"', OffsetDateTime.class);

        assertNotNull("The value should not be null.", value);
        assertIsEqual(date, value);
        assertEquals("The time zone is not correct.", getDefaultOffset(date), value.getOffset());
    }

    @Test
    public void testDeserializationAsString02WithTimeZoneTurnedOff() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.ofInstant(Instant.ofEpochSecond(123456789L, 183917322), Z2);
        ObjectMapper m = newMapper()
            .configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, false)
            .setTimeZone(TimeZone.getDefault());
        OffsetDateTime value = m.readValue('"' + FORMATTER.format(date) + '"', OffsetDateTime.class);

        assertNotNull("The value should not be null.", value);
        assertIsEqual(date, value);
        assertEquals("The time zone is not correct.", getOffset(value, Z2), value.getOffset());
    }

    @Test
    public void testDeserializationAsString03WithoutTimeZone() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.now(Z3);
        ObjectMapper m = newMapper()
                .configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, true);
        OffsetDateTime value = m.readValue('"' + FORMATTER.format(date) + '"', OffsetDateTime.class);

        assertNotNull("The value should not be null.", value);
        assertIsEqual(date, value);
        assertEquals("The time zone is not correct.", ZoneOffset.UTC, value.getOffset());
    }

    @Test
    public void testDeserializationAsString03WithTimeZone() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.now(Z3);
        ObjectMapper m = newMapper()
            .configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, true)
            .setTimeZone(TimeZone.getDefault());
        OffsetDateTime value = m.readValue('"' + FORMATTER.format(date) + '"', OffsetDateTime.class);

        assertNotNull("The value should not be null.", value);
        assertIsEqual(date, value);
        assertEquals("The time zone is not correct.", getDefaultOffset(date), value.getOffset());
    }

    @Test
    public void testDeserializationAsString03WithTimeZoneTurnedOff() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.now(Z3);
        ObjectMapper m = newMapper()
            .configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, false)
            .setTimeZone(TimeZone.getDefault());
        OffsetDateTime value = m.readValue('"' + FORMATTER.format(date) + '"', OffsetDateTime.class);

        assertNotNull("The value should not be null.", value);
        assertIsEqual(date, value);
        assertEquals("The time zone is not correct.", getOffset(value, Z3), value.getOffset());
    }

    @Test
    public void testDeserializationWithTypeInfo01WithoutTimeZone() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.ofInstant(Instant.ofEpochSecond(123456789L, 183917322), Z2);
        ObjectMapper m = newMapper()
                .addMixIn(Temporal.class, MockObjectConfiguration.class);
        Temporal value = m.readValue(
                "[\"" + OffsetDateTime.class.getName() + "\",123456789.183917322]", Temporal.class
                );

        assertNotNull("The value should not be null.", value);
        assertTrue("The value should be an OffsetDateTime.", value instanceof OffsetDateTime);
        assertIsEqual(date, (OffsetDateTime) value);
        assertEquals("The time zone is not correct.", ZoneOffset.UTC, ((OffsetDateTime) value).getOffset());
    }

    @Test
    public void testDeserializationWithTypeInfo01WithTimeZone() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.ofInstant(Instant.ofEpochSecond(123456789L, 183917322), Z2);
        ObjectMapper m = newMapper()
            .setTimeZone(TimeZone.getDefault())
            .addMixIn(Temporal.class, MockObjectConfiguration.class);
        Temporal value = m.readValue(
                "[\"" + OffsetDateTime.class.getName() + "\",123456789.183917322]", Temporal.class
                );

        assertNotNull("The value should not be null.", value);
        assertTrue("The value should be an OffsetDateTime.", value instanceof OffsetDateTime);
        assertIsEqual(date, (OffsetDateTime) value);
        assertEquals("The time zone is not correct.", getDefaultOffset(date), ((OffsetDateTime) value).getOffset());
    }

    @Test
    public void testDeserializationWithTypeInfo02WithoutTimeZone() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.ofInstant(Instant.ofEpochSecond(123456789L, 0), Z2);
        ObjectMapper m = newMapper()
            .configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, true)
            .addMixIn(Temporal.class, MockObjectConfiguration.class);
        Temporal value = m.readValue(
                "[\"" + OffsetDateTime.class.getName() + "\",123456789]", Temporal.class
                );

        assertNotNull("The value should not be null.", value);
        assertTrue("The value should be an OffsetDateTime.", value instanceof OffsetDateTime);
        assertIsEqual(date, (OffsetDateTime) value);
        assertEquals("The time zone is not correct.", ZoneOffset.UTC, ((OffsetDateTime) value).getOffset());
    }

    @Test
    public void testDeserializationWithTypeInfo02WithTimeZone() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.ofInstant(Instant.ofEpochSecond(123456789L, 0), Z2);
        ObjectMapper m = newMapper()
            .configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, true)
            .setTimeZone(TimeZone.getDefault())
            .addMixIn(Temporal.class, MockObjectConfiguration.class);
        Temporal value = m.readValue(
                "[\"" + OffsetDateTime.class.getName() + "\",123456789]", Temporal.class
                );

        assertNotNull("The value should not be null.", value);
        assertTrue("The value should be an OffsetDateTime.", value instanceof OffsetDateTime);
        assertIsEqual(date, (OffsetDateTime) value);
        assertEquals("The time zone is not correct.", getDefaultOffset(date), ((OffsetDateTime) value).getOffset());
    }

    @Test
    public void testDeserializationWithTypeInfo03WithoutTimeZone() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.ofInstant(Instant.ofEpochSecond(123456789L, 422000000), Z2);
        ObjectMapper m = newMapper()
            .configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, false)
            .addMixIn(Temporal.class, MockObjectConfiguration.class);
        Temporal value = m.readValue(
                "[\"" + OffsetDateTime.class.getName() + "\",123456789422]", Temporal.class
                );

        assertNotNull("The value should not be null.", value);
        assertTrue("The value should be an OffsetDateTime.", value instanceof OffsetDateTime);
        assertIsEqual(date, (OffsetDateTime) value);
        assertEquals("The time zone is not correct.", ZoneOffset.UTC, ((OffsetDateTime) value).getOffset());
    }

    @Test
    public void testDeserializationWithTypeInfo03WithTimeZone() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.ofInstant(Instant.ofEpochSecond(123456789L, 422000000), Z2);
        ObjectMapper m = newMapper()
            .configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, false)
            .setTimeZone(TimeZone.getDefault())
            .addMixIn(Temporal.class, MockObjectConfiguration.class);
        Temporal value = m.readValue(
                "[\"" + OffsetDateTime.class.getName() + "\",123456789422]", Temporal.class
                );

        assertNotNull("The value should not be null.", value);
        assertTrue("The value should be an OffsetDateTime.", value instanceof OffsetDateTime);
        assertIsEqual(date, (OffsetDateTime) value);
        assertEquals("The time zone is not correct.", getDefaultOffset(date), ((OffsetDateTime) value).getOffset());
    }

    @Test
    public void testDeserializationWithTypeInfo04WithoutTimeZone() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.now(Z3);
        ObjectMapper m = newMapper()
            .configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, true)
            .addMixIn(Temporal.class, MockObjectConfiguration.class);
        Temporal value = m.readValue(
                "[\"" + OffsetDateTime.class.getName() + "\",\"" + FORMATTER.format(date) + "\"]", Temporal.class
                );

        assertNotNull("The value should not be null.", value);
        assertTrue("The value should be an OffsetDateTime.", value instanceof OffsetDateTime);
        assertIsEqual(date, (OffsetDateTime) value);
        assertEquals("The time zone is not correct.", ZoneOffset.UTC, ((OffsetDateTime) value).getOffset());
    }

    @Test
    public void testDeserializationWithTypeInfo04WithTimeZone() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.now(Z3);
        ObjectMapper m = newMapper()
            .configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, true)
            .setTimeZone(TimeZone.getDefault())
            .addMixIn(Temporal.class, MockObjectConfiguration.class);
        Temporal value = m.readValue(
                "[\"" + OffsetDateTime.class.getName() + "\",\"" + FORMATTER.format(date) + "\"]", Temporal.class
                );

        assertNotNull("The value should not be null.", value);
        assertTrue("The value should be an OffsetDateTime.", value instanceof OffsetDateTime);
        assertIsEqual(date, (OffsetDateTime) value);
        assertEquals("The time zone is not correct.", getDefaultOffset(date), ((OffsetDateTime) value).getOffset());
    }

    @Test
    public void testDeserializationWithTypeInfo04WithTimeZoneTurnedOff() throws Exception
    {
        OffsetDateTime date = OffsetDateTime.now(Z3);

        ObjectMapper m = newMapper()
            .configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, false)
            .setTimeZone(TimeZone.getDefault())
            .addMixIn(Temporal.class, MockObjectConfiguration.class);
        Temporal value = m.readValue(
                "[\"" + OffsetDateTime.class.getName() + "\",\"" + FORMATTER.format(date) + "\"]", Temporal.class
                );

        assertNotNull("The value should not be null.", value);
        assertTrue("The value should be an OffsetDateTime.", value instanceof OffsetDateTime);
        OffsetDateTime cast = (OffsetDateTime) value;
        assertIsEqual(date, cast);
        assertEquals("The time zone is not correct.", getOffset(cast, Z3), cast.getOffset());
    }

    @Test
    public void testCustomPatternWithAnnotations() throws Exception
    {
        OffsetDateTime inputValue = OffsetDateTime.ofInstant(Instant.ofEpochSecond(0L), UTC);
        final Wrapper input = new Wrapper(inputValue);
        final ObjectMapper m = newMapper();
        String json = m.writeValueAsString(input);
        assertEquals(aposToQuotes("{'value':'1970_01_01T00:00:00+0000'}"), json);

        Wrapper result = m.readValue(json, Wrapper.class);
        assertEquals(input.value, result.value);
    }

    // [datatype-jsr310#79]
    @Test
    public void testRoundTripOfOffsetDateTimeAndJavaUtilDate() throws Exception
    {
        ObjectMapper mapper = newMapper();
        mapper.configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, false);
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        mapper.configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, false);

        Instant givenInstant = LocalDate.of(2016, 1, 1).atStartOfDay().atZone(ZoneOffset.UTC).toInstant();
        String json = mapper.writeValueAsString(java.util.Date.from(givenInstant));

        OffsetDateTime actual = mapper.readValue(json, OffsetDateTime.class); // this fails

        assertEquals(givenInstant.atOffset(ZoneOffset.UTC), actual);
    }

    private static void assertIsEqual(OffsetDateTime expected, OffsetDateTime actual)
    {
        assertTrue("The value is not correct. Expected timezone-adjusted <" + expected + ">, actual <" + actual + ">.",
                expected.isEqual(actual));
    }

    private static ZoneOffset getDefaultOffset(OffsetDateTime date)
    {
        return ZoneId.systemDefault().getRules().getOffset(date.toLocalDateTime());
    }

    private static ZoneOffset getOffset(OffsetDateTime date, ZoneId zone)
    {
        return zone.getRules().getOffset(date.toLocalDateTime());
    }
}

redpajama_set_name: RedPajamaGithub


text:
package org.atlasapi;

import com.datastax.driver.core.CodecRegistry;
import com.datastax.driver.extras.codecs.joda.InstantCodec;
import com.datastax.driver.extras.codecs.joda.LocalDateCodec;
import com.datastax.driver.extras.codecs.json.JacksonJsonCodec;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Predicates;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.metabroadcast.common.broker.BrokerFactory;
import com.metabroadcast.common.health.HealthProbe;
import com.metabroadcast.common.ids.IdGeneratorBuilder;
import com.metabroadcast.common.ids.SubstitutionTableNumberCodec;
import com.metabroadcast.common.persistence.cassandra.DatastaxCassandraService;
import com.metabroadcast.common.persistence.mongo.DatabasedMongo;
import com.metabroadcast.common.persistence.mongo.DatabasedMongoClient;
import com.metabroadcast.common.persistence.mongo.health.MongoConnectionPoolProbe;
import com.metabroadcast.common.properties.Configurer;
import com.metabroadcast.common.properties.Parameter;
import com.metabroadcast.common.queue.MessageSenders;
import com.metabroadcast.common.time.SystemClock;
import com.metabroadcast.sherlock.client.search.SherlockSearcher;
import com.metabroadcast.sherlock.common.config.ElasticSearchConfig;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.ReadPreference;
import com.mongodb.ServerAddress;
import com.netflix.astyanax.AstyanaxContext;
import com.netflix.astyanax.Keyspace;
import org.atlasapi.channel.ChannelGroupResolver;
import org.atlasapi.channel.ChannelResolver;
import org.atlasapi.content.AstyanaxCassandraContentStore;
import org.atlasapi.content.CassandraEquivalentContentStore;
import org.atlasapi.content.ContentSearcher;
import org.atlasapi.content.ContentStore;
import org.atlasapi.content.EquivalentContentStore;
import org.atlasapi.elasticsearch.SherlockSearchModule;
import org.atlasapi.elasticsearch.topic.SherlockPopularTopicSearcher;
import org.atlasapi.elasticsearch.topic.SherlockTopicSearcher;
import org.atlasapi.equivalence.EquivalenceGraphStore;
import org.atlasapi.event.EventResolver;
import org.atlasapi.event.EventWriter;
import org.atlasapi.hashing.HashGenerator;
import org.atlasapi.hashing.content.ContentHashGenerator;
import org.atlasapi.media.channel.CachingChannelGroupStore;
import org.atlasapi.media.channel.CachingChannelStore;
import org.atlasapi.media.channel.ChannelGroupStore;
import org.atlasapi.media.channel.MongoChannelGroupStore;
import org.atlasapi.media.channel.MongoChannelStore;
import org.atlasapi.media.channel.ServiceChannelStore;
import org.atlasapi.media.segment.MongoSegmentResolver;
import org.atlasapi.messaging.KafkaMessagingModule;
import org.atlasapi.neo4j.Neo4jModule;
import org.atlasapi.neo4j.service.Neo4jContentStore;
import org.atlasapi.organisation.OrganisationResolver;
import org.atlasapi.organisation.OrganisationStore;
import org.atlasapi.persistence.audit.NoLoggingPersistenceAuditLog;
import org.atlasapi.persistence.audit.PersistenceAuditLog;
import org.atlasapi.persistence.content.DefaultEquivalentContentResolver;
import org.atlasapi.persistence.content.EquivalentContentResolver;
import org.atlasapi.persistence.content.KnownTypeContentResolver;
import org.atlasapi.persistence.content.LookupResolvingContentResolver;
import org.atlasapi.persistence.content.mongo.MongoContentResolver;
import org.atlasapi.persistence.content.mongo.MongoContentWriter;
import org.atlasapi.persistence.content.mongo.MongoPlayerStore;
import org.atlasapi.persistence.content.mongo.MongoServiceStore;
import org.atlasapi.persistence.content.mongo.MongoTopicStore;
import org.atlasapi.persistence.content.organisation.MongoOrganisationStore;
import org.atlasapi.persistence.content.schedule.mongo.MongoScheduleStore;
import org.atlasapi.persistence.event.MongoEventStore;
import org.atlasapi.persistence.ids.MongoSequentialIdGenerator;
import org.atlasapi.persistence.lookup.TransitiveLookupWriter;
import org.atlasapi.persistence.lookup.mongo.MongoLookupEntryStore;
import org.atlasapi.persistence.player.CachingPlayerResolver;
import org.atlasapi.persistence.player.PlayerResolver;
import org.atlasapi.persistence.service.CachingServiceResolver;
import org.atlasapi.persistence.service.ServiceResolver;
import org.atlasapi.query.v4.schedule.OutputChannelGroupResolver;
import org.atlasapi.query.v4.search.PseudoEsEquivalentContentSearcher;
import org.atlasapi.schedule.EquivalentScheduleStore;
import org.atlasapi.schedule.ScheduleResolver;
import org.atlasapi.schedule.ScheduleStore;
import org.atlasapi.schedule.ScheduleWriter;
import org.atlasapi.segment.SegmentStore;
import org.atlasapi.system.MetricsModule;
import org.atlasapi.system.legacy.ContentListerResourceListerAdapter;
import org.atlasapi.system.legacy.LegacyChannelGroupResolver;
import org.atlasapi.system.legacy.LegacyChannelGroupTransformer;
import org.atlasapi.system.legacy.LegacyChannelResolver;
import org.atlasapi.system.legacy.LegacyChannelTransformer;
import org.atlasapi.system.legacy.LegacyContentLister;
import org.atlasapi.system.legacy.LegacyContentResolver;
import org.atlasapi.system.legacy.LegacyContentTransformer;
import org.atlasapi.system.legacy.LegacyEventResolver;
import org.atlasapi.system.legacy.LegacyLookupResolvingContentLister;
import org.atlasapi.system.legacy.LegacyOrganisationResolver;
import org.atlasapi.system.legacy.LegacyOrganisationTransformer;
import org.atlasapi.system.legacy.LegacyScheduleResolver;
import org.atlasapi.system.legacy.LegacySegmentMigrator;
import org.atlasapi.system.legacy.LegacyTopicLister;
import org.atlasapi.system.legacy.LegacyTopicResolver;
import org.atlasapi.system.legacy.PaTagMap;
import org.atlasapi.topic.TopicStore;
import org.atlasapi.util.CassandraSecondaryIndex;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Primary;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.List;
import java.util.UUID;

import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;

@Configuration
@Import({KafkaMessagingModule.class})
public class AtlasPersistenceModule {

    private static final String MONGO_COLLECTION_LOOKUP = "lookup";
    private static final String MONGO_COLLECTION_TOPICS = "topics";
    private static final ObjectMapper MAPPER = new ObjectMapper()
            .findAndRegisterModules()
            .disable(FAIL_ON_UNKNOWN_PROPERTIES);

    private static final PersistenceAuditLog persistenceAuditLog = new NoLoggingPersistenceAuditLog();
    private static final String STORE_METRIC_PREFIX = "persistence.store.";
    private static final String UTIL_METRIC_PREFIX = "persistence.util.";

    private final String mongoWriteHost = Configurer.get("mongo.write.host").get();
    private final Integer mongoWritePort = Configurer.get("mongo.write.port").toInt();
    private final String mongoWriteDbName = Configurer.get("mongo.write.name").get();

    private final String mongoReadHost = Configurer.get("mongo.read.host").get();
    private final Integer mongoReadPort = Configurer.get("mongo.read.port").toInt();
    private final String mongoReadDbName = Configurer.get("mongo.read.name").get();

    private final String cassandraCluster = Configurer.get("cassandra.cluster").get();
    private final String cassandraKeyspace = Configurer.get("cassandra.keyspace").get();
    private final String cassandraSeeds = Configurer.get("cassandra.seeds").get();
    private final String cassandraPort = Configurer.get("cassandra.port").get();
    private final String cassandraConnectionTimeout = Configurer.get("cassandra.connectionTimeout")
            .get();
    private final String cassandraClientThreads = Configurer.get("cassandra.clientThreads").get();
    private final Integer cassandraConnectionsPerHostLocal = Configurer.get(
            "cassandra.connectionsPerHost.local").toInt();
    private final Integer cassandraConnectionsPerHostRemote = Configurer.get(
            "cassandra.connectionsPerHost.remote").toInt();
    private final Integer cassandraDatastaxConnectionTimeout = Configurer.get(
            "cassandra.datastax.timeouts.connections").toInt();
    private final Integer cassandraDatastaxReadTimeout = Configurer.get(
            "cassandra.datastax.timeouts.read").toInt();

    private final String sherlockScheme = Configurer.get("sherlock.scheme").get();
    private final String sherlockHostname = Configurer.get("sherlock.hostname").get();
    private final Integer sherlockPort = Configurer.get("sherlock.port").toInt();
    private final Parameter processingConfig = Configurer.get("processing.config");

    private final String neo4jHost = Configurer.get("neo4j.host").get();
    private final Integer neo4jPort = Configurer.get("neo4j.port").toInt();
    private final Integer neo4jMaxIdleSessions = Configurer.get("neo4j.maxIdleSessions").toInt();

    private String equivalentContentChanges = Configurer
            .get("messaging.destination.equivalent.content.changes").get();
    private String equivalentContentGraphChanges = Configurer
            .get("messaging.destination.equivalent.content.graph.changes").get();

    private @Autowired BrokerFactory deerBrokerFactory;
    private @Autowired MetricsModule metricsModule;

    @PostConstruct
    public void init() {
        persistenceModule().startAsync().awaitRunning();

        // This is required to initialise the BackgroundComputingValue in the CachingChannelStore
        // otherwise we will get NPEs
        channelStore().start();
    }

    @PreDestroy
    public void tearDown() {
        channelStore().shutdown();
    }

    @Bean
    public CassandraPersistenceModule persistenceModule() {
        Iterable<String> seeds = Splitter.on(",").split(cassandraSeeds);
        ConfiguredAstyanaxContext contextSupplier = new ConfiguredAstyanaxContext(cassandraCluster,
                cassandraKeyspace,
                seeds,
                Integer.parseInt(cassandraPort),
                Integer.parseInt(cassandraClientThreads),
                Integer.parseInt(cassandraConnectionTimeout),
                metricsModule.metrics()
        );
        AstyanaxContext<Keyspace> context = contextSupplier.get();
        context.start();

        DatastaxCassandraService cassandraService = DatastaxCassandraService.builder()
                .withNodes(seeds)
                .withConnectionsPerHostLocal(cassandraConnectionsPerHostLocal)
                .withConnectionsPerHostRemote(cassandraConnectionsPerHostRemote)
                .withCodecRegistry(new CodecRegistry()
                        .register(InstantCodec.instance)
                        .register(LocalDateCodec.instance)
                        .register(new JacksonJsonCodec<>(
                                org.atlasapi.content.v2.model.Clip.Wrapper.class,
                                MAPPER
                        ))
                        .register(new JacksonJsonCodec<>(
                                org.atlasapi.content.v2.model.Encoding.Wrapper.class,
                                MAPPER
                        )))
                .withConnectTimeoutMillis(cassandraDatastaxConnectionTimeout)
                .withReadTimeoutMillis(cassandraDatastaxReadTimeout)
                .build();

        cassandraService.startAsync().awaitRunning();
        return CassandraPersistenceModule.builder()
                .withBrokerFactory(deerBrokerFactory)
                .withAstyanaxContext(context)
                .withDatastaxCassandraService(cassandraService)
                .withKeyspace(cassandraKeyspace)
                .withIdGeneratorBuilder(idGeneratorBuilder())
                .withContentHasher(ContentHashGenerator.create(
                        HashGenerator.create(),
                        UTIL_METRIC_PREFIX,
                        metricsModule.metrics()
                ))
                .withEventHasher(eventV2 -> UUID.randomUUID().toString())
                .withMetrics(metricsModule.metrics())
                .build();
    }

    @Bean
    public ContentStore contentStore() {
        return persistenceModule().contentStore();
    }

    public AstyanaxCassandraContentStore astyanaxContentStore() {
        return persistenceModule().astyanaxContentStore();
    }

    public ContentStore nullMessageSendingContentStore() {
        return persistenceModule().nullMessageSendingContentStore();
    }

    @Bean
    public TopicStore topicStore() {
        return persistenceModule().topicStore();
    }

    @Bean
    public ScheduleStore scheduleStore() {
        return persistenceModule().scheduleStore();
    }

    @Bean
    public SegmentStore segmentStore() {
        return persistenceModule().segmentStore();
    }

    @Bean
    public EventWriter eventWriter() {
        return persistenceModule().eventStore();
    }

    @Bean
    public EventResolver eventResolver() {
        return persistenceModule().eventStore();
    }

    @Bean
    public OrganisationStore organisationStore() {
        return persistenceModule().organisationStore();
    }

    @Bean
    public OrganisationStore idSettingOrganisationStore() {
        return persistenceModule().idSettingOrganisationStore();
    }

    @Bean
    public EquivalenceGraphStore getContentEquivalenceGraphStore() {
        return persistenceModule().contentEquivalenceGraphStore();
    }

    @Bean
    public EquivalenceGraphStore nullMessageSendingEquivalenceGraphStore() {
        return persistenceModule().nullMessageSendingEquivalenceGraphStore();
    }

    @Bean
    public EquivalentContentStore getEquivalentContentStore() {
        return new CassandraEquivalentContentStore(
                persistenceModule().contentStore(),
                legacyContentResolver(),
                persistenceModule().contentEquivalenceGraphStore(),
                persistenceModule().brokerSender(equivalentContentChanges),
                persistenceModule().brokerSender(equivalentContentGraphChanges),
                persistenceModule().getSession(),
                persistenceModule().getReadConsistencyLevel(),
                persistenceModule().getWriteConsistencyLevel(),
                metricsModule.metrics(),
                STORE_METRIC_PREFIX + "CassandraEquivalentContentStore."
        );
    }

    @Bean
    public EquivalentContentStore nullMessageSendingEquivalentContentStore() {
        return new CassandraEquivalentContentStore(
                persistenceModule().contentStore(),
                legacyContentResolver(),
                persistenceModule().contentEquivalenceGraphStore(),
                MessageSenders.noopSender(),
                MessageSenders.noopSender(),
                persistenceModule().getSession(),
                persistenceModule().getReadConsistencyLevel(),
                persistenceModule().getWriteConsistencyLevel(),
                metricsModule.metrics(),
                STORE_METRIC_PREFIX + "nullMessageSendingCassandraEquivalentContentStore."
        );
    }

    @Bean
    public EquivalentScheduleStore getEquivalentScheduleStore() {
        return persistenceModule().equivalentScheduleStore();
    }

    @Bean
    public SherlockSearchModule sherlockSearchModule() {
        return new SherlockSearchModule(
                sherlockElasticSearchConfig(),
                metricsModule.metrics(),
                outputChannelGroupResolver(),
                new CassandraSecondaryIndex(
                        persistenceModule().getSession(),
                        CassandraEquivalentContentStore.EQUIVALENT_CONTENT_INDEX,
                        persistenceModule().getReadConsistencyLevel()
                )
        );
    }

    @Bean
    @Primary
    public DatabasedMongo databasedReadMongo() {
        return new DatabasedMongo(mongo(mongoReadHost, mongoReadPort), mongoReadDbName);
    }

    @Bean
    @Primary
    public DatabasedMongoClient databasedReadMongoClient() {
        return new DatabasedMongoClient(mongo(mongoReadHost, mongoReadPort), mongoReadDbName);
    }

    @Bean
    public DatabasedMongo databasedWriteMongo() {
        return new DatabasedMongo(mongo(mongoWriteHost, mongoWritePort), mongoWriteDbName);
    }

    public MongoClient mongo(String mongoHost, Integer mongoPort) {

        MongoClientOptions.Builder mongoOptions = MongoClientOptions.builder()
                .connectionsPerHost(1000)
                .connectTimeout(10000);

        if (processingConfig == null || !processingConfig.toBoolean()) {
            mongoOptions.readPreference(ReadPreference.secondaryPreferred());
        }

        return new MongoClient(
                mongoHosts(mongoHost, mongoPort),
                mongoOptions.build()
        );
    }

    private IdGeneratorBuilder idGeneratorBuilder() {
        return sequenceIdentifier -> new MongoSequentialIdGenerator(
                databasedWriteMongo(),
                sequenceIdentifier
        );
    }

    @Bean
    @Primary
    public ContentSearcher equivContentSearcher() {
        return sherlockSearchModule().equivContentSearcher();
    }

    @Bean
    @Primary
    public SherlockTopicSearcher topicSearcher() {
        return sherlockSearchModule().topicSearcher();
    }

    @Bean
    @Primary
    public SherlockPopularTopicSearcher popularTopicSearcher() {
        return sherlockSearchModule().popularTopicSearcher();
    }

    @Bean
    @Primary
    public SherlockSearcher sherlockSearcher() {
        return sherlockSearchModule().getSherlockSearcher();
    }

    @Bean
    @Primary
    public PseudoEsEquivalentContentSearcher pseudoEquivalentSherlockSearcher() {
        return sherlockSearchModule().getPseudoEquivContentSearcher();
    }

    @Bean
    @Primary
    public ServiceChannelStore channelStore() {
        MongoChannelStore rawStore = new MongoChannelStore(
                databasedReadMongo(),
                channelGroupStore(),
                channelGroupStore()
        );
        return new CachingChannelStore(rawStore);
    }

    @Bean
    @Primary
    public ChannelGroupStore channelGroupStore() {
        return new CachingChannelGroupStore(
                new MongoChannelGroupStore(databasedReadMongo())
        );
    }

    private List<ServerAddress> mongoHosts(String mongoHost, final Integer mongoPort) {
        Splitter splitter = Splitter.on(",").omitEmptyStrings().trimResults();
        return ImmutableList.copyOf(Iterables.filter(Iterables.transform(
                splitter.split(mongoHost),
                input -> new ServerAddress(input, mongoPort)
        ), Predicates.notNull()));
    }

    @Bean
    HealthProbe mongoConnectionProbe() {
        return new MongoConnectionPoolProbe();
    }

    @Bean
    public ChannelResolver channelResolver() {
        return new LegacyChannelResolver(channelStore(), new LegacyChannelTransformer());
    }

    @Bean
    public ChannelGroupResolver channelGroupResolver() {
        return new LegacyChannelGroupResolver(
                channelGroupStore(),
                new LegacyChannelGroupTransformer()
        );
    }

    @Bean
    public OutputChannelGroupResolver outputChannelGroupResolver() {
        return new OutputChannelGroupResolver(channelGroupResolver());
    }

    @Bean
    public PlayerResolver playerResolver() {
        return new CachingPlayerResolver(new MongoPlayerStore(databasedReadMongo()));
    }

    @Bean
    public ServiceResolver serviceResolver() {
        return new CachingServiceResolver(new MongoServiceStore(databasedReadMongo()));
    }

    public LegacyContentResolver legacyContentResolver() {
        DatabasedMongo mongoDb = databasedReadMongo();
        KnownTypeContentResolver contentResolver = new MongoContentResolver(
                mongoDb,
                legacyEquivalenceStore()
        );
        return new LegacyContentResolver(
                legacyEquivalenceStore(),
                contentResolver,
                legacyContentTransformer()
        );
    }

    public MongoLookupEntryStore legacyEquivalenceStore() {
        return new MongoLookupEntryStore(
                databasedReadMongoClient(),
                MONGO_COLLECTION_LOOKUP,
                persistenceAuditLog,
                ReadPreference.primaryPreferred()
        );
    }

    public LegacySegmentMigrator legacySegmentMigrator() {
        return new LegacySegmentMigrator(legacySegmentResolver(), segmentStore());
    }

    private org.atlasapi.media.segment.SegmentResolver legacySegmentResolver() {
        return new MongoSegmentResolver(databasedReadMongo(), new SubstitutionTableNumberCodec());
    }

    public ScheduleWriter v2ScheduleStore() {
        return persistenceModule().v2ScheduleStore();
    }

    @Bean
    @Qualifier("legacy")
    public EventResolver legacyEventResolver() {
        return new LegacyEventResolver(new MongoEventStore(databasedReadMongo()), idSettingOrganisationStore());
    }

    @Bean
    @Qualifier("legacy")
    public ContentListerResourceListerAdapter legacyContentLister() {
        DatabasedMongo mongoDb = databasedReadMongo();
        DatabasedMongoClient mongoDbClient = databasedReadMongoClient();
        LegacyContentLister contentLister = new LegacyLookupResolvingContentLister(
                new MongoLookupEntryStore(
                        mongoDbClient,
                        MONGO_COLLECTION_LOOKUP,
                        persistenceAuditLog,
                        ReadPreference.secondary()
                ),
                new MongoContentResolver(mongoDb, legacyEquivalenceStore())
        );
        return new ContentListerResourceListerAdapter(
                contentLister,
                legacyContentTransformer()
        );
    }

    @Bean
    @Qualifier("legacy")
    public LegacyContentTransformer legacyContentTransformer() {
        return new LegacyContentTransformer(
                channelStore(),
                legacySegmentMigrator(),
                new PaTagMap(
                        legacyTopicStore(),
                        new MongoSequentialIdGenerator(databasedWriteMongo(),
                                MONGO_COLLECTION_TOPICS
                        )));
    }

    @Bean
    @Qualifier("legacy")
    public LegacyTopicLister legacyTopicLister() {
        return new LegacyTopicLister(legacyTopicStore());
    }

    @Bean
    @Qualifier("legacy")
    public MongoTopicStore legacyTopicStore() {
        return new MongoTopicStore(databasedReadMongo(), persistenceAuditLog);
    }

    // disable Bean as this breaks API spring construction
    public LegacyTopicResolver legacyTopicResolver() {
        return new LegacyTopicResolver(legacyTopicStore(), legacyTopicStore());
    }

    @Bean
    @Qualifier("legacy")
    public OrganisationResolver legacyOrganisationResolver() {
        TransitiveLookupWriter lookupWriter = TransitiveLookupWriter.generatedTransitiveLookupWriter(
                legacyEquivalenceStore());
        MongoOrganisationStore store = new MongoOrganisationStore(databasedReadMongo(),
                lookupWriter,
                legacyEquivalenceStore(),
                persistenceAuditLog);
        LegacyOrganisationTransformer transformer = new LegacyOrganisationTransformer();
        return new LegacyOrganisationResolver(store, transformer);
    }

    @Bean
    @Qualifier("legacy")
    public ScheduleResolver legacyScheduleStore() {
        DatabasedMongo db = databasedReadMongo();
        KnownTypeContentResolver contentResolver = new MongoContentResolver(
                db,
                legacyEquivalenceStore()
        );
        LookupResolvingContentResolver resolver = new LookupResolvingContentResolver(
                contentResolver,
                legacyEquivalenceStore()
        );
        MongoContentWriter contentWriter = new MongoContentWriter(
                db, legacyEquivalenceStore(), persistenceAuditLog,
                playerResolver(), serviceResolver(), new SystemClock()
        );
        EquivalentContentResolver equivalentContentResolver = new DefaultEquivalentContentResolver(
                contentResolver,
                legacyEquivalenceStore()
        );
        return new LegacyScheduleResolver(
                new MongoScheduleStore(
                        db,
                        channelStore(),
                        resolver,
                        contentWriter,
                        equivalentContentResolver,
                        MessageSenders.noopSender()
                ),
                legacyContentTransformer()
        );
    }

    @Bean
    public Neo4jModule neo4jModule() {
        return Neo4jModule.create(
            neo4jHost, neo4jPort, neo4jMaxIdleSessions
        );
    }

    @Bean
    public Neo4jContentStore neo4jContentStore() {
        return neo4jModule().neo4jContentStore(metricsModule.metrics());
    }

    @Bean
    public ElasticSearchConfig sherlockElasticSearchConfig() {
        return ElasticSearchConfig.builder()
                .withScheme(sherlockScheme)
                .withHostname(sherlockHostname)
                .withPort(sherlockPort)
                .build();
    }
}


text:
process.env.NODE_ENV = 'test';

const chai = require('chai');
const should = chai.should();
const chaiHttp = require('chai-http');
const server = require('../../src/server/app');
const knex = require('../../src/server/db/connection');
const tokens = require('../tokens');

chai.use(chaiHttp);

describe('routes : integration', () => {
    beforeEach(() => {
        return knex.migrate.rollback().then(() => {
            return knex.migrate.latest();
        });

    });
    afterEach(() => {
        return knex.migrate.rollback();
    });

    it('User is able to register, log in, create a commune and create a chore', (done) => {
        var token = "";
        // register
        chai.request(server).post('/auth/register').send({username: "tester", password: "tester"}).end((err, res) => {
            should.not.exist(err);
            logIn();
        })
        function logIn() {
            chai.request(server).post('/auth/login').send({username: "tester", password: "tester"}).end((err, res) => {
                should.not.exist(err);
                should.exist(res.body.contents.token);
                token = "JWT " + res.body.contents.token;
                createCommune();
            });
        }
        function createCommune() {
            chai.request(server).post('/communes').set('Authorization', token).send({commune_name: "testCommune"}).end((err, res) => {
                should.not.exist(err);
                createChore();
            });
        }
        function createChore() {
          chai.request(server).post('/chores').set('Authorization', token).send({name: "testChore", priority: 1, points: 1}).end((err, res) => {
              should.not.exist(err);
              createPurchase();
          });
        }
        function createPurchase() {
          chai.request(server).post('/purchases').set('Authorization', token).send({description: "testPurchase", amount: 1.99}).end((err, res) => {
              should.not.exist(err);
              getCommune();
          });
        }
        function getCommune() {
          chai.request(server).get('/communes').set('Authorization', token).send().end((err, res) => {
              should.not.exist(err);
              var commune = res.body.contents;
              commune.commune_id.should.equal(1);
              getChores();
          });
        }

        function getChores() {
            chai.request(server).get('/chores').set('Authorization', token).send().end((err, res) => {
                should.not.exist(err);
                var chores = res.body.contents;
                chores.length.should.equal(1);
                getPurchases();
            });
        }

        function getPurchases() {
            chai.request(server).get('/purchases').set('Authorization', token).send().end((err, res) => {
                should.not.exist(err);
                var purchases = res.body.contents;
                purchases.length.should.equal(1);
                deleteChore();
            });
        }

        function deleteChore() {
          chai.request(server).delete('/chores/1').set('Authorization', token).send().end((err, res) => {
              should.not.exist(err);
              deletePurchase();
          });
        }

        function deletePurchase() {
          chai.request(server).delete('/purchases/1').set('Authorization', token).send().end((err, res) => {
              should.not.exist(err);
              getChores2();
          });
        }

        function getChores2(){
          chai.request(server).get('/chores').set('Authorization', token).send().end((err, res) => {
              should.not.exist(err);
              var chores = res.body.contents;
              chores.length.should.equal(0);
              getPurchases2();
          });
        }

        function getPurchases2(){
            chai.request(server).get('/purchases').set('Authorization', token).send().end((err, res) => {
                should.not.exist(err);
                var purchases = res.body.contents;
                purchases.length.should.equal(2);
                done();
            });
        }

    });

});


text:
layout: page
title: Latest Posts
excerpt: "A simple and clean responsive Jekyll theme for words and photos."
search_omit: true
#image:
#  feature: home.jpg
#  credit: Luis Llerena
#  creditlink: https://stocksnap.io/photo/3ZHG0XOIT6
---

{% for post in site.posts limit:10 %}

{{ post.title }} <time datetime="{{ post.date | date_to_xmlschema }}">{{ post.date | date: "%B %d, %Y" }}</time>{% if post.excerpt %} {{ post.excerpt }}{% endif %}

{% endfor %}


text:
'use strict';
var fs = require('fs');
var path = require('path');
var decryptionPvk = fs.readFileSync(path.join(__dirname, '/../env/xxx-dev.nursing.duke.edu.pem'), 'ascii');
module.exports = {
  app: {
    title: 'Duson SEAN - Staging Environment',
    description: 'Application for Candidates, Faculty and Staff of DUSON',
    keywords: 'Duke, Duke University, FRS, Faculty Recruitment'
  },
  saml: {
    path: '/auth/saml/callback',
    entryPoint: 'https://shib.oit.duke.edu/idp/profile/SAML2/Redirect/SSO',
    callbackURL: 'https://xxx-dev.nursing.duke.edu/auth/saml/callback',
    issuer: 'https://xxx-dev.nursing.duke.edu',
    identifierFormat: 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient',
    decryptionPvk: decryptionPvk
  },
  sequelizeSettings: {
    host: 'localhost',
    dialect: 'mysql',
    database: 'your_database_dev',
    username: 'your_db_user',
    password: 'password'
  }
};


text:
'use strict';
angular.module( 'mmBusinessPartner' )
	.provider( '$mmBusinessPartnerConfig', function() {
		this.$get = function() {
			return {
				'canDoThis': true,
			};
		};
	} )
	.config( [
		'$mmApiProvider',
		function($mmApiProvider) {
			$mmApiProvider.addRoute( 'website', 'company', '/Account/Company' );
			$mmApiProvider.addRoute( 'website', 'addresses', '/Account/Addresses' );
			$mmApiProvider.addRoute( 'website', 'contacts', '/Account/Contacts' );
		},
	] )

	.run( [
		'$rootScope',
		'mmBusinessPartner',
		'ngAuth',
		function($rootScope, mmBusinessPartner, ngAuth) {
			$rootScope.$on( 'api.module.notify', function(event, data) {
				//mmBusinessPartner.cart.items = data.mmBusinessPartner.items;
			} );
			$rootScope.$on( 'authentication:endSession', function() {
				mmBusinessPartner.$destroy();
			} );

			$rootScope.$on( 'authentication:newSession', function(name, data) {
				mmBusinessPartner.$restore();
			} );

			$rootScope.$on( 'mmBusinessPartner:change', function(name, data) {
				mmBusinessPartner.$save();
			} );

			ngAuth.isLoggedIn().then( function(value) {
				if (!empty( value )) {
					mmBusinessPartner.$construct();
				}
			} );
		},
	] );


text:
<!DOCTYPE html>

  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=9">
  <title>myRetail Shop</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="app.css">


text: A sorting hat app for Harry Potter with house score capability


text:
@interface DDBlurPresenter ()<DDBlurPresentationControllerDelegate>

@property(nonatomic,strong)DDBlurPresentationController * animationController;
@end

@implementation DDBlurPresenter
-(instancetype)init{
    self = [super init];
    if (self) {
        _blurStyle = UIBlurEffectStyleDark;
    }
    return  self;
}
-(DDBlurPresentationController *)presentationControllerForPresentedViewController:(UIViewController *)presented presentingViewController:(UIViewController *)presenting sourceViewController:(UIViewController *)source{
    if (!self.animationController) {
        self.animationController = [[DDBlurPresentationController alloc] initWithPresentedViewController:presented presentingViewController:presenting style:self.blurStyle];
        self.animationController.dd_presentationDelegate = self;
    }
    return self.animationController;
}
-(id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source{

    DDBlurTransitioning *transition = [DDBlurTransitioning new];
    transition.isPresentation = YES;
    return transition;
}
-(id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed{
    DDBlurTransitioning *transition = [DDBlurTransitioning new];
    transition.isPresentation = NO;
    return transition;
}
- (void)setBlurStyle:(UIBlurEffectStyle)blurStyle {
    if (_blurStyle != blurStyle) {
        _blurStyle = blurStyle;
        self.animationController.blurStyle = blurStyle;
    }
}
//代理方法
-(void)presentationControllerDidDismissed:(DDBlurPresentationController *)controller {
    self.animationController = nil;
}
@end


text:
package org.apache.catalina.loader;

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;

public class EchoTag extends TagSupport {
    private static final long serialVersionUID = 1L;

    private String echo = null;

    public void setEcho(String echo) {
        this.echo = echo;
    }

    public String getEcho() {
        return echo;
    }

    @Override
    public int doStartTag() throws JspException {
        try {
            pageContext.getOut().print("<p>" + echo + "</p>");
        } catch (IOException e) {
            throw new JspException(e);
        }
        return super.doStartTag();
    }
}


text:
title: 'Hubo-in-the-Browser'
layout: "regular-layout"
isPage: true
---

Hubo-in-the-Browser
===================

This is the project page for Hubo-in-the-Browser, aka hubo-js. The goal of the project is to bring the humanoid robot Hubo, developed at KAIST and worked on at many US institutions as well, to the largest audience possible: the entire Internet.

Here is a short presentation about the project:

Examples
--------

If you are at this page, I assume you are looking for the demos. All the demos are simple static HTML/JavaScript pages, so you can see all the source code by using the "View Source" option in your web browser. All the source code is also found in the Github repository.

> [mouseclick]({local_root}examples/mouseclick/index.html): Identify which link of Hubo is clicked by the mouse.
>
> [color-picker.html]({local_root}examples/color-picker/color-picker.html): Demo of the highlighting and color changing API.
>
> [trajectory_playback.html]({local_root}examples/trajectory_playback/trajectory_playback.html): Play the Rainbox, Inc mocap demos.
>
> [sliders.html]({local_root}examples/sliders/sliders.html): Position upper body joints with slider controls.
>
> [minimal.html]({local_root}examples/minimal/minimal.html): Minimalistic demo with single joint movement.
>
> [really_minimal.html]({local_root}examples/minimal/really_minimal.html): Embed hubo in an `<iframe>`.

Features
--------

Hubo-js is a fledgling robot simulator, and features are being added as the need arises.

* 3D display using WebGL that supports rotate, pan, and zoom.
* 58 joints that can be directly controlled using JavaScript.
* 40 degrees of freedom (matching the 40 motors on Hubo) that can be controlled using JavaScript.
  * The abstraction reduces the working DOF in the fingers.
* That's all for now.

Planned future features:

* Self-collision detection using THREE.js Rays
* Various inverse kinematic frameworks
* A mouse API to simplify writing code where users click or drag links and joints.

Using
-----

Checkout the Github repository (<http://github.com/wmhilton/hubo-js>) and look for instructions there.

Help Out
--------

Want to help with the project? Email <wmhilton@gmail.com>