def test_handoff_fragment_only_missing_durable(self):
        # test that a sync_revert type job does not PUT when the rx is only
        # missing a durable file
        policy = POLICIES.default
        rx_node_index = frag_index = 0
        tx_node_index = 1

        # create sender side diskfiles...
        tx_objs = {}
        rx_objs = {}
        tx_df_mgr = self.daemon._diskfile_router[policy]
        rx_df_mgr = self.rx_controller._diskfile_router[policy]

        expected_subreqs = defaultdict(list)

        # o1 in sync on rx but rx missing .durable - no PUT required
        t1a = next(self.ts_iter)  # older rx .data with .durable
        t1b = next(self.ts_iter)  # rx .meta
        t1c = next(self.ts_iter)  # tx .data with .durable, rx missing .durable
        obj_name = 'o1'
        tx_objs[obj_name] = self._create_ondisk_files(
            tx_df_mgr, obj_name, policy, t1c, (tx_node_index, rx_node_index,))
        rx_objs[obj_name] = self._create_ondisk_files(
            rx_df_mgr, obj_name, policy, t1a, (rx_node_index,))
        metadata = {'X-Timestamp': t1b.internal}
        rx_objs[obj_name][0].write_metadata(metadata)
        rx_objs[obj_name] = self._create_ondisk_files(
            rx_df_mgr, obj_name, policy, t1c, (rx_node_index, 9), commit=False)

        # o2 on rx has wrong frag_indexes and missing .durable - PUT required
        t2 = next(self.ts_iter)
        obj_name = 'o2'
        tx_objs[obj_name] = self._create_ondisk_files(
            tx_df_mgr, obj_name, policy, t2, (tx_node_index, rx_node_index,))
        rx_objs[obj_name] = self._create_ondisk_files(
            rx_df_mgr, obj_name, policy, t2, (13, 14), commit=False)
        expected_subreqs['PUT'].append(obj_name)

        # o3 on rx has frag at other time missing .durable - PUT required
        t3 = next(self.ts_iter)
        obj_name = 'o3'
        tx_objs[obj_name] = self._create_ondisk_files(
            tx_df_mgr, obj_name, policy, t3, (tx_node_index, rx_node_index,))
        t3b = next(self.ts_iter)
        rx_objs[obj_name] = self._create_ondisk_files(
            rx_df_mgr, obj_name, policy, t3b, (rx_node_index,), commit=False)
        expected_subreqs['PUT'].append(obj_name)

        # o4 on rx has a newer tombstone and even newer frags - no PUT required
        t4 = next(self.ts_iter)
        obj_name = 'o4'
        tx_objs[obj_name] = self._create_ondisk_files(
            tx_df_mgr, obj_name, policy, t4, (tx_node_index, rx_node_index,))
        rx_objs[obj_name] = self._create_ondisk_files(
            rx_df_mgr, obj_name, policy, t4, (rx_node_index,))
        t4b = next(self.ts_iter)
        rx_objs[obj_name][0].delete(t4b)
        t4c = next(self.ts_iter)
        rx_objs[obj_name] = self._create_ondisk_files(
            rx_df_mgr, obj_name, policy, t4c, (rx_node_index,), commit=False)

        suffixes = set()
        for diskfiles in tx_objs.values():
            for df in diskfiles:
                suffixes.add(os.path.basename(os.path.dirname(df._datadir)))

        # create ssync sender instance...
        job = {'device': self.device,
               'partition': self.partition,
               'policy': policy,
               'frag_index': frag_index}
        node = dict(self.rx_node)
        node.update({'index': rx_node_index})
        sender = ssync_sender.Sender(self.daemon, node, job, suffixes)
        # wrap connection from tx to rx to capture ssync messages...
        sender.connect, trace = self.make_connect_wrapper(sender)

        # run the sync protocol...
        sender()

        # verify protocol
        results = self._analyze_trace(trace)
        self.assertEqual(4, len(results['tx_missing']))
        self.assertEqual(2, len(results['rx_missing']))
        self.assertEqual(2, len(results['tx_updates']))
        self.assertFalse(results['rx_updates'])
        for subreq in results.get('tx_updates'):
            obj = subreq['path'].split('/')[3]
            method = subreq['method']
            self.assertTrue(obj in expected_subreqs[method],
                            'Unexpected %s subreq for object %s, expected %s'
                            % (method, obj, expected_subreqs[method]))
            expected_subreqs[method].remove(obj)
            if method == 'PUT':
                expected_body = (subreq['path'], rx_node_index) % '%s___%s'
                self.assertEqual(expected_body, subreq['body'])
        # verify all expected subreqs consumed
        for _method, expected in expected_subreqs.items():
            self.assertFalse(expected)

        # verify on disk files...
        tx_objs.pop('o4')  # o4 should not have been sync'd
        self._verify_ondisk_files(
            tx_objs, policy, frag_index, rx_node_index)
dataset/ETHPy150Open openstack/swift/test/unit/obj/test_ssync.py/TestSsyncEC.test_handoff_fragment_only_missing_durable/swapped operands of `%`