trema/trema-edge

View on GitHub
unittests/lib/openflow_application_interface_test.c

Summary

Maintainability
Test Coverage
/*
 * Unit tests for OpenFlow Application Interface.
 *
 * Author: Yasunobu Chiba
 *
 * Copyright (C) 2008-2013 NEC Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License, version 2, as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */


#include <openflow.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "bool.h"
#include "checks.h"
#include "cmockery_trema.h"
#include "hash_table.h"
#include "linked_list.h"
#include "log.h"
#include "messenger.h"
#include "openflow_application_interface.h"
#include "openflow_message.h"
#include "stat.h"
#include "wrapper.h"


/********************************************************************************
 * Helpers.
 ********************************************************************************/

typedef struct {
  char key[ STAT_KEY_LENGTH ];
  uint64_t value;
} stat_entry;


extern bool openflow_application_interface_initialized;
extern openflow_event_handlers_t event_handlers;
extern char service_name[ MESSENGER_SERVICE_NAME_LENGTH ];
extern hash_table *stats;

extern void assert_if_not_initialized();
extern void handle_error( const uint64_t datapath_id, buffer *data );
extern void handle_experimenter_error( const uint64_t datapath_id, buffer *data );
extern void handle_echo_reply( const uint64_t datapath_id, buffer *data );
extern void handle_experimenter( const uint64_t datapath_id, buffer *data );
extern void handle_features_reply( const uint64_t datapath_id, buffer *data );
extern void handle_get_config_reply( const uint64_t datapath_id, buffer *data );
extern void handle_packet_in( const uint64_t datapath_id, buffer *data );
extern void handle_flow_removed( const uint64_t datapath_id, buffer *data );
extern void handle_port_status( const uint64_t datapath_id, buffer *data );
extern void handle_multipart_reply( const uint64_t datapath_id, buffer *data );
extern void handle_stats_reply( const uint64_t datapath_id, buffer *data );
extern void handle_barrier_reply( const uint64_t datapath_id, buffer *data );
extern void handle_queue_get_config_reply( const uint64_t datapath_id, buffer *data );
extern void handle_role_reply( const uint64_t datapath_id, buffer *data );
extern void handle_get_async_reply( const uint64_t datapath_id, buffer *data );
extern void dump_buf( const buffer *data );
extern void handle_switch_events( uint16_t type, void *data, size_t length );
extern void handle_openflow_message( void *data, size_t length );
extern void handle_message( uint16_t type, void *data, size_t length );
extern void insert_dpid( list_element **head, uint64_t *dpid );
extern void handle_list_switches_reply( uint16_t message_type, void *data, size_t length, void *user_data );


#define SWITCH_READY_HANDLER ( ( void * ) 0x00020001 )
#define SWITCH_READY_USER_DATA ( ( void * ) 0x00020011 )
#define SWITCH_DISCONNECTED_HANDLER ( ( void * ) 0x00020002 )
#define SWITCH_DISCONNECTED_USER_DATA ( ( void * ) 0x00020021 )
#define ERROR_HANDLER ( ( void * ) 0x00010001 )
#define ERROR_USER_DATA ( ( void * ) 0x00010011 )
#define EXPERIMENTER_ERROR_HANDLER ( ( void * ) 0x00010002 )
#define EXPERIMENTER_ERROR_USER_DATA ( ( void * ) 0x00010021 )
#define ECHO_REPLY_HANDLER ( ( void * ) 0x00010003 )
#define ECHO_REPLY_USER_DATA ( ( void * ) 0x00010031 )
#define EXPERIMENTER_HANDLER ( ( void * ) 0x00010004 )
#define EXPERIMENTER_USER_DATA ( ( void * ) 0x00010041 )
#define FEATURES_REPLY_HANDLER ( ( void * ) 0x00010005 )
#define FEATURES_REPLY_USER_DATA ( ( void * ) 0x00010051 )
#define GET_CONFIG_REPLY_HANDLER ( ( void * ) 0x00010006 )
#define GET_CONFIG_REPLY_USER_DATA ( ( void * ) 0x00010061 )
#define PACKET_IN_HANDLER ( ( void * ) 0x00010007 )
#define PACKET_IN_USER_DATA ( ( void * ) 0x00010071 )
#define FLOW_REMOVED_HANDLER ( ( void * ) 0x00010008 )
#define FLOW_REMOVED_USER_DATA ( ( void * ) 0x00010081 )
#define PORT_STATUS_HANDLER ( ( void * ) 0x00010009 )
#define PORT_STATUS_USER_DATA ( ( void * ) 0x00010091 )
#define MULTIPART_REPLY_HANDLER ( ( void * ) 0x0001000a )
#define MULTIPART_REPLY_USER_DATA ( ( void * ) 0x000100a1 )
#define BARRIER_REPLY_HANDLER ( ( void * ) 0x0001000b )
#define BARRIER_REPLY_USER_DATA ( ( void * ) 0x000100b1 )
#define QUEUE_GET_CONFIG_REPLY_HANDLER ( ( void * ) 0x0001000c )
#define QUEUE_GET_CONFIG_REPLY_USER_DATA ( ( void * ) 0x000100c1 )
#define ROLE_REPLY_HANDLER ( ( void * ) 0x0001000d )
#define ROLE_REPLY_USER_DATA ( ( void * ) 0x000100d1 )
#define GET_ASYNC_REPLY_HANDLER ( ( void * ) 0x0001000e )
#define GET_ASYNC_REPLY_USER_DATA ( ( void * ) 0x000100e1 )
#define LIST_SWITCHES_REPLY_HANDLER ( ( void * ) 0x0001000f )
#define LIST_SWITCHES_REPLY_USER_DATA ( ( void * ) 0x000100f1 )


static const pid_t PID = 12345;
static char SERVICE_NAME[] = "learning switch application 0";

static openflow_event_handlers_t NULL_EVENT_HANDLERS = { false, ( void * ) 0, ( void * ) 0,
                                                         ( void * ) 0, ( void * ) 0,
                                                         ( void * ) 0, ( void * ) 0,
                                                         ( void * ) 0, ( void * ) 0,
                                                         ( void * ) 0, ( void * ) 0,
                                                         ( void * ) 0, ( void * ) 0,
                                                         ( void * ) 0, ( void * ) 0,
                                                         ( void * ) 0, ( void * ) 0,
                                                         false, ( void * ) 0, ( void * ) 0,
                                                         false, ( void * ) 0, ( void * ) 0,
                                                         ( void * ) 0, ( void * ) 0,
                                                         ( void * ) 0, ( void * ) 0,
                                                         ( void * ) 0, ( void * ) 0,
                                                         ( void * ) 0, ( void * ) 0,
                                                         ( void * ) 0, ( void * ) 0,
                                                         ( void * ) 0, ( void * ) 0,
                                                         ( void * ) 0 };

static openflow_event_handlers_t EVENT_HANDLERS = {
  false, SWITCH_READY_HANDLER, SWITCH_READY_USER_DATA,
  SWITCH_DISCONNECTED_HANDLER, SWITCH_DISCONNECTED_USER_DATA,
  ERROR_HANDLER, ERROR_USER_DATA,
  EXPERIMENTER_ERROR_HANDLER, EXPERIMENTER_ERROR_USER_DATA,
  ECHO_REPLY_HANDLER, ECHO_REPLY_USER_DATA,
  EXPERIMENTER_HANDLER, EXPERIMENTER_USER_DATA,
  FEATURES_REPLY_HANDLER, FEATURES_REPLY_USER_DATA,
  GET_CONFIG_REPLY_HANDLER, GET_CONFIG_REPLY_USER_DATA,
  false, PACKET_IN_HANDLER, PACKET_IN_USER_DATA,
  false, FLOW_REMOVED_HANDLER, FLOW_REMOVED_USER_DATA,
  PORT_STATUS_HANDLER, PORT_STATUS_USER_DATA,
  MULTIPART_REPLY_HANDLER, MULTIPART_REPLY_USER_DATA,
  BARRIER_REPLY_HANDLER, BARRIER_REPLY_USER_DATA,
  QUEUE_GET_CONFIG_REPLY_HANDLER, QUEUE_GET_CONFIG_REPLY_USER_DATA,
  ROLE_REPLY_HANDLER, ROLE_REPLY_USER_DATA,
  GET_ASYNC_REPLY_HANDLER, GET_ASYNC_REPLY_USER_DATA,
  LIST_SWITCHES_REPLY_HANDLER
};
static uint64_t DATAPATH_ID = 0x0102030405060708ULL;
static char REMOTE_SERVICE_NAME[] = "switch.0x102030405060708";
static const uint32_t TRANSACTION_ID = 0x04030201;
static const uint32_t VENDOR_ID = 0xccddeeff;
static const uint8_t MAC_ADDR_X[ OFP_ETH_ALEN ] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
static const uint8_t MAC_ADDR_Y[ OFP_ETH_ALEN ] = { 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d };
static const char *PORT_NAME = "port 1";
static const uint32_t PORT_FEATURES = ( OFPPF_10MB_HD | OFPPF_10MB_FD | OFPPF_100MB_HD |
                                        OFPPF_100MB_FD | OFPPF_1GB_HD | OFPPF_1GB_FD |
                                        OFPPF_10GB_FD | OFPPF_40GB_FD | OFPPF_100GB_FD |
                                        OFPPF_1TB_FD | OFPPF_OTHER |  OFPPF_COPPER |
                                        OFPPF_FIBER | OFPPF_AUTONEG | OFPPF_PAUSE | OFPPF_PAUSE_ASYM );

#define USER_DATA_LEN 64
static uint8_t USER_DATA[ USER_DATA_LEN ];


static bool packet_in_handler_called = false;


/********************************************************************************
 * Mocks.
 ********************************************************************************/

const char*
mock_get_trema_name() {
  return "TEST_SERVICE_NAME";
}


pid_t
mock_getpid() {
  return PID;
}


bool
mock_init_openflow_message() {
  return ( bool ) mock();
}


bool
mock_add_message_received_callback( char *service_name,
                                    void ( *callback )( uint16_t tag, void *data, size_t len ) ) {
  check_expected( service_name );
  check_expected( callback );

  return ( bool ) mock();
}


bool
mock_add_message_replied_callback( char *service_name,
                                   void ( *callback )( uint16_t tag, void *data, size_t len, void *user_data ) ) {
  check_expected( service_name );
  check_expected( callback );

  return ( bool ) mock();
}


bool
mock_send_message( char *service_name, uint16_t tag, void *data, size_t len ) {
  uint32_t tag32 = tag;

  check_expected( service_name );
  check_expected( tag32 );
  check_expected( data );
  check_expected( len );

  return ( bool ) mock();
}


bool
mock_send_request_message( char *to_service_name, char *from_service_name, uint16_t tag,
                           void *data, size_t len, void *user_data ) {
  uint32_t tag32 = tag;

  check_expected( to_service_name );
  check_expected( from_service_name );
  check_expected( tag32 );
  check_expected( data );
  check_expected( len );
  check_expected( user_data );

  return ( bool ) mock();
}


bool
mock_delete_message_received_callback( char *service_name,
                                       void ( *callback )( uint16_t tag, void *data, size_t len ) ) {
  check_expected( service_name );
  check_expected( callback );

  return ( bool ) mock();
}


bool
mock_delete_message_replied_callback( char *service_name,
                                      void ( *callback )( uint16_t tag, void *data, size_t len, void *user_data ) ) {
  check_expected( service_name );
  check_expected( callback );

  return ( bool ) mock();
}


bool
mock_clear_send_queue( const char *service_name ) {
  check_expected( service_name );

  return ( bool ) mock();
}


bool
mock_parse_packet( buffer *buf ) {
  calloc_packet_info( buf );
  return ( bool ) mock();
}


static void
mock_switch_disconnected_handler( uint64_t datapath_id, void *user_data ) {
  check_expected( &datapath_id );
  check_expected( user_data );
}

static void
mock_error_handler( uint64_t datapath_id, uint32_t transaction_id, uint16_t type, uint16_t code,
                    const buffer *data, void *user_data ) {
  uint32_t type32 = type;
  uint32_t code32 = code;

  check_expected( &datapath_id );
  check_expected( transaction_id );
  check_expected( type32 );
  check_expected( code32 );
  check_expected( data->length );
  check_expected( data->data );
  check_expected( user_data );
}


static void
mock_experimenter_error_handler( uint64_t datapath_id, uint32_t transaction_id, uint16_t type,
                                 uint16_t exp_type, uint32_t experimenter,
                                 const buffer *data, void *user_data ) {
  uint32_t type32 = type;
  uint32_t exp_type32 = exp_type;

  check_expected( &datapath_id );
  check_expected( transaction_id );
  check_expected( type32 );
  check_expected( exp_type32 );
  check_expected( experimenter );
  check_expected( data->length );
  check_expected( data->data );
  check_expected( user_data );
}

static void
mock_echo_reply_handler( uint64_t datapath_id, uint32_t transaction_id, const buffer *data,
                         void *user_data ){
  void *data_uc;

  check_expected( &datapath_id );
  check_expected( transaction_id );
  if( data != NULL ) {
    check_expected( data->length );
    check_expected( data->data );
  }
  else {
    data_uc = ( void * ) ( unsigned long ) data;
    check_expected( data_uc );
  }
  check_expected( user_data );
}


static void
mock_experimenter_handler( uint64_t datapath_id, uint32_t transaction_id, uint32_t experimenter,
                           uint32_t exp_type, const buffer *data, void *user_data ){
  void *data_uc;

  check_expected( &datapath_id );
  check_expected( transaction_id );
  check_expected( experimenter );
  check_expected( exp_type );
  if( data != NULL ) {
    check_expected( data->length );
    check_expected( data->data );
  }
  else {
    data_uc = ( void * ) ( unsigned long ) data;
    check_expected( data_uc );
  }
  check_expected( user_data );
}


static void
mock_features_reply_handler( uint64_t datapath_id, uint32_t transaction_id,
                             uint32_t n_buffers, uint8_t n_tables, uint8_t auxiliary_id,
                             uint32_t capabilities, void *user_data ) {
  uint32_t n_tables32 = n_tables;
  uint32_t auxiliary_id32 = auxiliary_id;

  check_expected( &datapath_id );
  check_expected( transaction_id );
  check_expected( n_buffers );
  check_expected( n_tables32 );
  check_expected( auxiliary_id32 );
  check_expected( capabilities );
  check_expected( user_data );
}

static void
mock_get_config_reply_handler( uint64_t datapath_id, uint32_t transaction_id,
                               uint16_t flags, uint16_t miss_send_len, void *user_data ) {
  uint32_t flags32 = flags;
  uint32_t miss_send_len32 = miss_send_len;

  check_expected( &datapath_id );
  check_expected( transaction_id );
  check_expected( flags32 );
  check_expected( miss_send_len32 );
  check_expected( user_data );
}


static void
mock_packet_in_handler(
  uint64_t datapath_id,
  uint32_t transaction_id,
  uint32_t buffer_id,
  uint16_t total_len,
  uint8_t reason,
  uint8_t table_id,
  uint64_t cookie,
  const oxm_matches *match,
  const buffer *data,
  void *user_data
) {
  uint32_t total_len32 = total_len;
  uint32_t reason32 = reason;
  uint32_t table_id32 = table_id;
  oxm_match_header *match1, *match2;
  
  match1 = match->list->data;
  match2 = match->list->next->data;
  
  check_expected( &datapath_id );
  check_expected( transaction_id );
  check_expected( buffer_id );
  check_expected( total_len32 );
  check_expected( reason32 );
  check_expected( table_id32 );
  check_expected( &cookie );
  check_expected( match1 );
  check_expected( match2 );
  if ( data != NULL ) {
    check_expected( data->length );
    check_expected( data->data );
  }
  else {
    void *data_uc = ( void * ) ( unsigned long ) data;
    check_expected( data_uc );
  }
  check_expected( user_data );

  packet_in_handler_called = true;
}


static void
mock_simple_packet_in_handler( uint64_t dpid, packet_in event ) {
  uint64_t datapath_id = dpid;
  uint32_t transaction_id = event.transaction_id;
  uint32_t buffer_id = event.buffer_id;
  uint32_t total_len32 = event.total_len;
  uint32_t reason32 = event.reason;
  uint32_t table_id32 = event.table_id;
  uint64_t cookie = event.cookie;
  const oxm_matches *match = event.match;
  const buffer *data = event.data;
  void *user_data = event.user_data;
  oxm_match_header *match1, *match2;

  match1 = match->list->data;
  match2 = match->list->next->data;
  
  check_expected( &datapath_id );
  check_expected( transaction_id );
  check_expected( buffer_id );
  check_expected( total_len32 );
  check_expected( reason32 );
  check_expected( table_id32 );
  check_expected( &cookie );
  check_expected( match1 );
  check_expected( match2 );
  check_expected( data->length );
  check_expected( user_data );

  packet_in_handler_called = true;
}


static void
mock_flow_removed_handler( uint64_t datapath_id, uint32_t transaction_id, uint64_t cookie, uint16_t priority,
                           uint8_t reason, uint8_t table_id, uint32_t duration_sec, uint32_t duration_nsec,
                           uint16_t idle_timeout, uint16_t hard_timeout, uint64_t packet_count, uint64_t byte_count,
                           const oxm_matches *match, void *user_data ) {
  uint32_t priority32 = priority;
  uint32_t reason32 = reason;
  uint32_t table_id32 = table_id;
  uint32_t idle_timeout32 = idle_timeout;
  uint32_t hard_timeout32 = hard_timeout;
  oxm_match_header *match1, *match2;
  
  match1 = match->list->data;
  match2 = match->list->next->data;

  check_expected( &datapath_id );
  check_expected( transaction_id );
  check_expected( &cookie );
  check_expected( priority32 );
  check_expected( reason32 );
  check_expected( table_id32 );
  check_expected( duration_sec );
  check_expected( duration_nsec );
  check_expected( idle_timeout32 );
  check_expected( hard_timeout32 );
  check_expected( &packet_count );
  check_expected( &byte_count );
  check_expected( match1 );
  check_expected( match2 );
  check_expected( user_data );
}


static void
mock_simple_flow_removed_handler( uint64_t datapath_id, flow_removed message ) {
  uint32_t transaction_id = message.transaction_id;
  uint64_t cookie = message.cookie;
  uint32_t priority32 = message.priority;
  uint32_t reason32 = message.reason;
  uint32_t table_id32 = message.table_id;
  uint32_t duration_sec = message.duration_sec;
  uint32_t duration_nsec = message.duration_nsec;
  uint32_t idle_timeout32 = message.idle_timeout;
  uint32_t hard_timeout32 = message.hard_timeout;
  uint64_t packet_count = message.packet_count;
  uint64_t byte_count = message.byte_count;
  const oxm_matches *match = message.match;
  void *user_data = message.user_data;
  oxm_match_header *match1, *match2;

  match1 = match->list->data;
  match2 = match->list->next->data;

  check_expected( &datapath_id );
  check_expected( transaction_id );
  check_expected( &cookie );
  check_expected( priority32 );
  check_expected( reason32 );
  check_expected( table_id32 );
  check_expected( duration_sec );
  check_expected( duration_nsec );
  check_expected( idle_timeout32 );
  check_expected( hard_timeout32 );
  check_expected( &packet_count );
  check_expected( &byte_count );
  check_expected( match1 );
  check_expected( match2 );
  check_expected( user_data );
}


static void
mock_port_status_handler( uint64_t datapath_id, uint32_t transaction_id, uint8_t reason,
                          struct ofp_port desc, void *user_data ) {
  uint32_t reason32 = reason;

  check_expected( &datapath_id );
  check_expected( transaction_id );
  check_expected( reason32 );
  check_expected( &desc );
  check_expected( user_data );
}


static void
mock_multipart_reply_handler( uint64_t datapath_id, uint32_t transaction_id, uint16_t type,
                              uint16_t flags, const buffer *data, void *user_data ) {
  uint32_t type32 = type;
  uint32_t flags32 = flags;

  check_expected( &datapath_id );
  check_expected( transaction_id );
  check_expected( type32 );
  check_expected( flags32 );
  check_expected( data->length );
  check_expected( data->data );
  check_expected( user_data );
}


static void
mock_barrier_reply_handler( uint64_t datapath_id, uint32_t transaction_id, void *user_data ) {
  check_expected( &datapath_id );
  check_expected( transaction_id );
  check_expected( user_data );
}

static void
mock_queue_get_config_reply_handler( uint64_t datapath_id, uint32_t transaction_id,
                                     uint32_t port, const list_element *queues, void *user_data ) {
  struct ofp_packet_queue *queue1, *queue2;

  queue1 = queues->data;
  queue2 = queues->next->data;

  check_expected( &datapath_id );
  check_expected( transaction_id );
  check_expected( port );
  check_expected( queue1 );
  check_expected( queue2 );
  check_expected( user_data );
}

static void
mock_role_reply_handler( uint64_t datapath_id, uint32_t transaction_id, uint32_t role, uint64_t generation_id, void *user_data ) {
  check_expected( &datapath_id );
  check_expected( transaction_id );
  check_expected( role );
  check_expected( &generation_id );
  check_expected( user_data );
}


static void
mock_get_async_reply_handler( uint64_t datapath_id, uint32_t transaction_id, uint32_t packet_in_mask[2], uint32_t port_status_mask[2],
                              uint32_t flow_removed_mask[2], void *user_data ) {
  check_expected( &datapath_id );
  check_expected( transaction_id );
  check_expected( packet_in_mask );
  check_expected( port_status_mask );
  check_expected( flow_removed_mask );
  check_expected( user_data );
}

static void
mock_handle_list_switches_reply( const list_element *switches, void *user_data ) {
  uint64_t *dpid1, *dpid2, *dpid3;

  if ( switches != NULL ) {
    dpid1 = switches->data;
    check_expected( *dpid1 );
    if ( switches->next != NULL ) {
      dpid2 = switches->next->data;
      check_expected( *dpid2 );
      if ( switches->next->next != NULL ) {
        dpid3 = switches->next->next->data;
        check_expected( *dpid3 );
      }
    }
  }
  check_expected( user_data );
}


void
mock_die( char *format, ... ) {
  check_expected( format );
  mock_assert( false, "die", __FILE__, __LINE__ );
}


void
mock_debug( char *format, ... ) {
  UNUSED( format );
}


void
mock_info( char *format, ... ) {
  UNUSED( format );
}


void
mock_warn( char *format, ... ) {
  UNUSED( format );
}


void
mock_error( char *format, ... ) {
  UNUSED( format );
}


void
mock_critical( char *format, ... ) {
  UNUSED( format );
}


static int
mock_get_logging_level() {
  return LOG_DEBUG;
}


/********************************************************************************
 * Common function.
 ********************************************************************************/

static oxm_match_header *oxm_match_testdata[2] = { NULL, NULL };
static uint16_t oxm_match_testdata_len[2] = { 0, 0 };
struct ofp_match *expected_ofp_match = NULL;
static uint16_t expected_ofp_match_len = 0;


static void
delete_oxm_match_testdata( void ) {
  if ( oxm_match_testdata[0] != NULL ) {
    xfree( oxm_match_testdata[0] );
    oxm_match_testdata[0] = NULL;
  }
  if ( oxm_match_testdata[1] != NULL ) {
    xfree( oxm_match_testdata[1] );
    oxm_match_testdata[1] = NULL;
  }
  if ( expected_ofp_match != NULL ) {
    xfree( expected_ofp_match );
    expected_ofp_match = NULL;
  }
  memset( oxm_match_testdata_len, 0, sizeof( oxm_match_testdata_len ) );
  expected_ofp_match_len = 0;
}


static void
create_oxm_match_testdata( void ) {
  uint16_t offset = sizeof( oxm_match_header );
  uint32_t type;
  uint16_t match_len;
  uint32_t *val32;
  oxm_match_header *match;
  struct ofp_match *ofp_match;
  uint16_t ofp_match_len;
  uint16_t ofp_match_len_with_pad;
  void *v;

  delete_oxm_match_testdata();

  type = OXM_OF_IN_PORT;
  match_len = ( uint16_t ) ( offset + OXM_LENGTH( type ) );
  match = ( oxm_match_header * ) xcalloc( 1, match_len );
  *match = type;
  val32 = ( uint32_t * ) ( ( char * ) match + offset );
  *val32 = 0x01020304;

  oxm_match_testdata[0] = match;
  oxm_match_testdata_len[0] = match_len;


  type = OXM_OF_IN_PHY_PORT;
  match_len = ( uint16_t ) ( offset + OXM_LENGTH( type ) );
  match = ( oxm_match_header * ) xcalloc( 1, match_len );
  *match = type;
  val32 = ( uint32_t * ) ( ( char * ) match + offset );
  *val32 = 0x05060708;

  oxm_match_testdata[1] = match;
  oxm_match_testdata_len[1] = match_len;

  ofp_match_len = ( uint16_t ) ( offsetof( struct ofp_match, oxm_fields )
                                + oxm_match_testdata_len[0]
                                + oxm_match_testdata_len[1] );
  ofp_match_len_with_pad = ( uint16_t ) ( ofp_match_len + PADLEN_TO_64( ofp_match_len ) );
  ofp_match = ( struct ofp_match * ) xcalloc( 1, ofp_match_len_with_pad );
  ofp_match->type = OFPMT_OXM;
  ofp_match->length = ofp_match_len;
  v = ( char * ) ofp_match + offsetof( struct ofp_match, oxm_fields );
  memcpy( v, oxm_match_testdata[0], oxm_match_testdata_len[0] );
  v = ( char * ) v + oxm_match_testdata_len[0];
  memcpy( v, oxm_match_testdata[1], oxm_match_testdata_len[1] );

  expected_ofp_match = ofp_match;
  expected_ofp_match_len = ofp_match_len_with_pad;
}


static struct ofp_instruction *instruction_testdata[2] = { NULL, NULL };
static uint16_t instruction_testdata_len[2] = { 0, 0 };
struct ofp_instruction *expected_ofp_instruction = NULL;
static uint16_t expected_ofp_instruction_len = 0;


static void
delete_instruction_testdata( void ) {
  if ( instruction_testdata[0] != NULL ) {
    xfree( instruction_testdata[0] );
    instruction_testdata[0] = NULL;
  }
  if ( instruction_testdata[1] != NULL ) {
    xfree( instruction_testdata[1] );
    instruction_testdata[1] = NULL;
  }
  if ( expected_ofp_instruction != NULL ) {
    xfree( expected_ofp_instruction );
    expected_ofp_instruction = NULL;
  }
  memset( instruction_testdata_len, 0, sizeof( instruction_testdata_len ) );
  expected_ofp_instruction_len = 0;
}


static void
create_instruction_testdata( void ) {
  uint16_t instruction_len;
  uint16_t ofp_instruction_len;
  struct ofp_instruction *inst;
  struct ofp_instruction_meter *instruction;
  void *d;

  delete_instruction_testdata();

  instruction_len = ( uint16_t ) ( sizeof( struct ofp_instruction_meter ) );
  instruction = ( struct ofp_instruction_meter * ) xcalloc( 1, instruction_len );
  instruction->type = OFPIT_METER;
  instruction->len = instruction_len;
  instruction->meter_id = 0x01020304;

  instruction_testdata[0] = ( struct ofp_instruction * ) instruction;
  instruction_testdata_len[0] = instruction_len;


  instruction_len = ( uint16_t ) ( sizeof( struct ofp_instruction_meter ) );
  instruction = ( struct ofp_instruction_meter * ) xcalloc( 1, instruction_len );
  instruction->type = OFPIT_METER;
  instruction->len = instruction_len;
  instruction->meter_id = 0x05060708;

  instruction_testdata[1] = ( struct ofp_instruction * ) instruction;
  instruction_testdata_len[1] = instruction_len;

  ofp_instruction_len = ( uint16_t ) ( instruction_testdata_len[0] + instruction_testdata_len[1] );
  inst = ( struct ofp_instruction * ) xcalloc( 1, ofp_instruction_len );
  memcpy( inst, instruction_testdata[0], instruction_testdata_len[0] );
  d = ( char * ) inst + instruction_testdata_len[0];
  memcpy( d, instruction_testdata[1], instruction_testdata_len[1] );

  expected_ofp_instruction = inst;
  expected_ofp_instruction_len = ofp_instruction_len;
}


static struct ofp_bucket *bucket_testdata[2] = { NULL, NULL };
static uint16_t bucket_testdata_len[2] = { 0, 0 };


static void
delete_bucket_testdata( void ) {
  if ( bucket_testdata[0] != NULL ) {
    xfree( bucket_testdata[0] );
    bucket_testdata[0] = NULL;
  }
  if ( bucket_testdata[1] != NULL ) {
    xfree( bucket_testdata[1] );
    bucket_testdata[1] = NULL;
  }
  memset( bucket_testdata_len, 0, sizeof( bucket_testdata_len ) );
}


static void
create_bucket_testdata( void ) {
  uint16_t action_len;
  uint16_t bucket_len;
  struct ofp_bucket *bucket;
  struct ofp_action_output *act;

  delete_bucket_testdata();

  action_len = sizeof( struct ofp_action_output );
  bucket_len = ( uint16_t ) ( offsetof( struct ofp_bucket, actions ) + action_len );
  bucket = ( struct ofp_bucket * ) xcalloc( 1, bucket_len );
  bucket->len = bucket_len;
  bucket->weight = 0x1234;
  bucket->watch_port = 0x11223344;
  bucket->watch_group = 0x55667788;
  act = ( struct ofp_action_output * ) bucket->actions;
  act->type = OFPAT_OUTPUT;
  act->len = action_len;
  act->port = 0x01020304;
  act->max_len = 0x0506;

  bucket_testdata[0] = ( struct ofp_bucket * ) bucket;
  bucket_testdata_len[0] = bucket_len;


  action_len = sizeof( struct ofp_action_output );
  bucket_len = ( uint16_t ) ( offsetof( struct ofp_bucket, actions ) + action_len );
  bucket = ( struct ofp_bucket * ) xcalloc( 1, bucket_len );
  bucket->len = bucket_len;
  bucket->weight = 0x5678;
  bucket->watch_port = 0x12233445;
  bucket->watch_group = 0x56677889;
  act = ( struct ofp_action_output * ) bucket->actions;
  act->type = OFPAT_OUTPUT;
  act->len = action_len;
  act->port = 0x0708090A;
  act->max_len = 0x0B0C;

  bucket_testdata[1] = ( struct ofp_bucket * ) bucket;
  bucket_testdata_len[1] = bucket_len;
}


/********************************************************************************
 * Setup and teardown function.
 ********************************************************************************/

static void
cleanup() {
  openflow_application_interface_initialized = false;
  packet_in_handler_called = false;

  memset( service_name, 0, sizeof( service_name ) );
  memset( &event_handlers, 0, sizeof( event_handlers ) );
  memset( USER_DATA, 'Z', sizeof( USER_DATA ) );
  if ( stats != NULL ) {
    delete_hash( stats );
    stats = NULL;
  }
}


static void
init() {
  bool ret;

  get_logging_level = mock_get_logging_level;

  cleanup();

  will_return( mock_init_openflow_message, true );

  expect_string( mock_add_message_received_callback, service_name, SERVICE_NAME );
  expect_value( mock_add_message_received_callback, callback, handle_message );
  will_return( mock_add_message_received_callback, true );

  expect_string( mock_add_message_replied_callback, service_name, SERVICE_NAME );
  expect_value( mock_add_message_replied_callback, callback, handle_list_switches_reply );
  will_return( mock_add_message_replied_callback, true );

  init_stat();

  ret = init_openflow_application_interface( SERVICE_NAME );

  assert_true( ret );
  assert_true( openflow_application_interface_initialized );
  assert_string_equal( service_name, SERVICE_NAME );
  assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) );
}


/********************************************************************************
 * init_openflow_application_interface() tests.
 ********************************************************************************/

static void
test_init_openflow_application_interface_with_valid_custom_service_name() {
  bool ret;

  will_return( mock_init_openflow_message, true );

  expect_string( mock_add_message_received_callback, service_name, SERVICE_NAME );
  expect_value( mock_add_message_received_callback, callback, handle_message );
  will_return( mock_add_message_received_callback, true );

  expect_string( mock_add_message_replied_callback, service_name, SERVICE_NAME );
  expect_value( mock_add_message_replied_callback, callback, handle_list_switches_reply );
  will_return( mock_add_message_replied_callback, true );

  ret = init_openflow_application_interface( SERVICE_NAME );

  assert_true( ret );
  assert_true( openflow_application_interface_initialized );
  assert_string_equal( service_name, SERVICE_NAME );
  assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) );
}


static void
test_init_openflow_application_interface_with_too_long_custom_service_name() {
  bool ret;
  char too_long_service_name[ MESSENGER_SERVICE_NAME_LENGTH + 1 ];
  char expected_service_name[ MESSENGER_SERVICE_NAME_LENGTH ];

  memset( too_long_service_name, 'a', sizeof( too_long_service_name ) );
  too_long_service_name[ MESSENGER_SERVICE_NAME_LENGTH ] = '\0';

  memset( expected_service_name, '\0', sizeof( expected_service_name ) );

  ret = init_openflow_application_interface( too_long_service_name );

  assert_true( ret == false );
  assert_true( openflow_application_interface_initialized == false );
  assert_string_equal( service_name, expected_service_name );
  assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) );
}


static void
test_init_openflow_application_interface_if_already_initialized() {
  bool ret;

  ret = set_openflow_event_handlers( EVENT_HANDLERS );

  assert_true( ret );
  assert_memory_equal( &event_handlers, &EVENT_HANDLERS, sizeof( event_handlers ) );

  ret = init_openflow_application_interface( SERVICE_NAME );

  assert_true( ret == false );
  assert_true( openflow_application_interface_initialized == true );
  assert_string_equal( service_name, SERVICE_NAME );
  assert_memory_equal( &event_handlers, &EVENT_HANDLERS, sizeof( event_handlers ) );
}


/********************************************************************************
 * init_openflow_application_interface() tests.
 ********************************************************************************/

static void
test_finalize_openflow_application_interface() {
  bool ret;
  char expected_service_name[ MESSENGER_SERVICE_NAME_LENGTH ];

  memset( expected_service_name, '\0', sizeof( expected_service_name ) );

  expect_string( mock_delete_message_received_callback, service_name, SERVICE_NAME );
  expect_value( mock_delete_message_received_callback, callback, handle_message );
  will_return( mock_delete_message_received_callback, true );

  expect_string( mock_delete_message_replied_callback, service_name, SERVICE_NAME );
  expect_value( mock_delete_message_replied_callback, callback, handle_list_switches_reply );
  will_return( mock_delete_message_replied_callback, true );

  ret = finalize_openflow_application_interface();

  assert_true( ret );
  assert_true( openflow_application_interface_initialized == false );
  assert_string_equal( service_name, expected_service_name );
  assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) );
}


static void
test_finalize_openflow_application_interface_if_not_initialized() {
  char expected_service_name[ MESSENGER_SERVICE_NAME_LENGTH ];

  memset( expected_service_name, '\0', sizeof( expected_service_name ) );

  expect_assert_failure( finalize_openflow_application_interface() );

  assert_true( openflow_application_interface_initialized == false );
  assert_string_equal( service_name, expected_service_name );
  assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) );
}


/********************************************************************************
 * set_openflow_event_handlers() tests.
 ********************************************************************************/

static void
test_set_openflow_event_handlers() {
  bool ret;

  ret = set_openflow_event_handlers( EVENT_HANDLERS );

  assert_true( ret );
  assert_memory_equal( &event_handlers, &EVENT_HANDLERS, sizeof( event_handlers ) );
}


/********************************************************************************
 * Switch ready handler tests.
 ********************************************************************************/

static void
mock_switch_ready_handler( uint64_t datapath_id, void *user_data ) {
  check_expected( &datapath_id );
  check_expected( user_data );
}


static void
mock_simple_switch_ready_handler( switch_ready event ) {
  uint64_t datapath_id = event.datapath_id;
  void *user_data = event.user_data;

  check_expected( &datapath_id );
  check_expected( user_data );
}


static void
test_set_switch_ready_handler() {
  char user_data[] = "Ready!";
  set_switch_ready_handler( mock_switch_ready_handler, user_data );
  assert_true( event_handlers.switch_ready_callback == mock_switch_ready_handler );
  assert_string_equal( event_handlers.switch_ready_user_data, user_data );
}


static void
test_set_simple_switch_ready_handler() {
  char user_data[] = "Ready!";
  set_switch_ready_handler( mock_simple_switch_ready_handler, user_data );
  assert_true( event_handlers.switch_ready_callback == mock_simple_switch_ready_handler );
  assert_string_equal( event_handlers.switch_ready_user_data, user_data );
}


static void
test_set_switch_ready_handler_should_die_if_handler_is_NULL() {
  char user_data[] = "Ready!";
  expect_string( mock_die, format, "Invalid callback function for switch_ready event." );
  expect_assert_failure( set_switch_ready_handler( NULL, user_data ) );
  assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) );
}


static void
test_handle_switch_ready() {
  char user_data[] = "Ready!";
  buffer *data = alloc_buffer_with_length( sizeof( openflow_service_header_t ) );
  uint64_t *datapath_id = append_back_buffer( data, sizeof( openflow_service_header_t ) );
  *datapath_id = htonll( DATAPATH_ID );

  expect_memory( mock_switch_ready_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_string( mock_switch_ready_handler, user_data, user_data );

  set_switch_ready_handler( mock_switch_ready_handler, user_data );
  handle_message( MESSENGER_OPENFLOW_READY, data->data, data->length );

  stat_entry *stat = lookup_hash_entry( stats, "openflow_application_interface.switch_ready_receive_succeeded" );
  assert_int_equal( ( int ) stat->value, 1 );

  free_buffer( data );
  xfree( delete_hash_entry( stats, "openflow_application_interface.switch_ready_receive_succeeded" ) );
}


static void
test_handle_switch_ready_with_simple_handler() {
  char user_data[] = "Ready!";
  buffer *data = alloc_buffer_with_length( sizeof( openflow_service_header_t ) );
  uint64_t *datapath_id = append_back_buffer( data, sizeof( openflow_service_header_t ) );
  *datapath_id = htonll( DATAPATH_ID );

  expect_memory( mock_simple_switch_ready_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_string( mock_simple_switch_ready_handler, user_data, user_data );

  set_switch_ready_handler( mock_simple_switch_ready_handler, user_data );
  handle_message( MESSENGER_OPENFLOW_READY, data->data, data->length );

  stat_entry *stat = lookup_hash_entry( stats, "openflow_application_interface.switch_ready_receive_succeeded" );
  assert_int_equal( ( int ) stat->value, 1 );

  free_buffer( data );
  xfree( delete_hash_entry( stats, "openflow_application_interface.switch_ready_receive_succeeded" ) );
}


/********************************************************************************
 * set_switch_disconnected_handler() tests.
 ********************************************************************************/

static void
test_set_switch_disconnected_handler() {
  assert_true( set_switch_disconnected_handler( SWITCH_DISCONNECTED_HANDLER, SWITCH_DISCONNECTED_USER_DATA ) );
  assert_int_equal( event_handlers.switch_disconnected_callback, SWITCH_DISCONNECTED_HANDLER );
  assert_int_equal( event_handlers.switch_disconnected_user_data, SWITCH_DISCONNECTED_USER_DATA );
}


static void
test_set_switch_disconnected_handler_if_handler_is_NULL() {
  expect_string( mock_die, format, "Callback function ( switch_disconnected_handler ) must not be NULL." );
  expect_assert_failure( set_switch_disconnected_handler( NULL, NULL ) );
  assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) );
}


/********************************************************************************
 * set_error_handler() tests.
 ********************************************************************************/

static void
test_set_error_handler() {
  assert_true( set_error_handler( ERROR_HANDLER, ERROR_USER_DATA ) );
  assert_int_equal( event_handlers.error_callback, ERROR_HANDLER );
  assert_int_equal( event_handlers.error_user_data, ERROR_USER_DATA );
}


static void
test_set_error_handler_if_handler_is_NULL() {
  expect_string( mock_die, format, "Callback function ( error_handler ) must not be NULL." );
  expect_assert_failure( set_error_handler( NULL, NULL ) );
  assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) );
}


/********************************************************************************
 * set_experimenter_error_handler() tests.
 ********************************************************************************/

static void
test_set_experimenter_error_handler() {
  assert_true( set_experimenter_error_handler( EXPERIMENTER_ERROR_HANDLER, EXPERIMENTER_ERROR_USER_DATA ) );
  assert_int_equal( event_handlers.experimenter_error_callback, EXPERIMENTER_ERROR_HANDLER );
  assert_int_equal( event_handlers.experimenter_error_user_data, EXPERIMENTER_ERROR_USER_DATA );
}


static void
test_set_experimenter_error_handler_if_handler_is_NULL() {
  expect_string( mock_die, format, "Callback function ( experimenter_error_handler ) must not be NULL." );
  expect_assert_failure( set_experimenter_error_handler( NULL, NULL ) );
  assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) );
}


/********************************************************************************
 * set_echo_reply_handler() tests.
 ********************************************************************************/

static void
test_set_echo_reply_handler() {
  assert_true( set_echo_reply_handler( ECHO_REPLY_HANDLER, ECHO_REPLY_USER_DATA ) );
  assert_int_equal( event_handlers.echo_reply_callback, ECHO_REPLY_HANDLER );
  assert_int_equal( event_handlers.echo_reply_user_data, ECHO_REPLY_USER_DATA );
}


static void
test_set_echo_reply_handler_if_handler_is_NULL() {
  expect_string( mock_die, format, "Callback function ( echo_reply_handler ) must not be NULL." );
  expect_assert_failure( set_echo_reply_handler( NULL, NULL ) );
  assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) );
}


/********************************************************************************
 * set_experimenter_handler() tests.
 ********************************************************************************/

static void
test_set_experimenter_handler() {
  assert_true( set_experimenter_handler( EXPERIMENTER_HANDLER, EXPERIMENTER_USER_DATA ) );
  assert_int_equal( event_handlers.experimenter_callback, EXPERIMENTER_HANDLER );
  assert_int_equal( event_handlers.experimenter_user_data, EXPERIMENTER_USER_DATA );
}


static void
test_set_experimenter_handler_if_handler_is_NULL() {
  expect_string( mock_die, format, "Callback function ( experimenter_handler ) must not be NULL." );
  expect_assert_failure( set_experimenter_handler( NULL, NULL ) );
  assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) );
}


/********************************************************************************
 * set_features_reply_handler() tests.
 ********************************************************************************/

static void
test_set_features_reply_handler() {
  assert_true( set_features_reply_handler( FEATURES_REPLY_HANDLER, FEATURES_REPLY_USER_DATA ) );
  assert_int_equal( event_handlers.features_reply_callback, FEATURES_REPLY_HANDLER );
  assert_int_equal( event_handlers.features_reply_user_data, FEATURES_REPLY_USER_DATA );
}


static void
test_set_features_reply_handler_if_handler_is_NULL() {
  expect_string( mock_die, format, "Callback function ( features_reply_handler ) must not be NULL." );
  expect_assert_failure( set_features_reply_handler( NULL, NULL ) );
  assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) );
}


/********************************************************************************
 * set_get_config_reply_handler() tests.
 ********************************************************************************/

static void
test_set_get_config_reply_handler() {
  assert_true( set_get_config_reply_handler( GET_CONFIG_REPLY_HANDLER, GET_CONFIG_REPLY_USER_DATA ) );
  assert_int_equal( event_handlers.get_config_reply_callback, GET_CONFIG_REPLY_HANDLER );
  assert_int_equal( event_handlers.get_config_reply_user_data, GET_CONFIG_REPLY_USER_DATA );
}


static void
test_set_get_config_reply_handler_if_handler_is_NULL() {
  expect_string( mock_die, format, "Callback function ( get_config_reply_handler ) must not be NULL." );
  expect_assert_failure( set_get_config_reply_handler( NULL, NULL ) );
  assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) );
}


/********************************************************************************
 * Packet in handler tests.
 ********************************************************************************/
static void
test_set_packet_in_handler() {
  set_packet_in_handler( mock_packet_in_handler, PACKET_IN_USER_DATA );
  assert_true( event_handlers.packet_in_callback == mock_packet_in_handler );
  assert_true( event_handlers.packet_in_user_data == PACKET_IN_USER_DATA );
}


static void
test_set_simple_packet_in_handler() {
  set_packet_in_handler( mock_simple_packet_in_handler, PACKET_IN_USER_DATA );
  assert_true( event_handlers.packet_in_callback == mock_simple_packet_in_handler );
  assert_true( event_handlers.packet_in_user_data == PACKET_IN_USER_DATA );
}


static void
test_set_packet_in_handler_should_die_if_handler_is_NULL() {
  expect_string( mock_die, format, "Callback function ( packet_in_handler ) must not be NULL." );
  expect_assert_failure( set_packet_in_handler( NULL, PACKET_IN_USER_DATA ) );
  assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) );
}


/********************************************************************************
 * set_flow_removed_handler() tests.
 ********************************************************************************/
static void
test_set_flow_removed_handler() {
  set_flow_removed_handler( mock_flow_removed_handler, FLOW_REMOVED_USER_DATA );
  assert_true( event_handlers.flow_removed_callback == mock_flow_removed_handler );
  assert_true( event_handlers.flow_removed_user_data == FLOW_REMOVED_USER_DATA );
}


static void
test_set_simple_flow_removed_handler() {
  set_flow_removed_handler( mock_simple_flow_removed_handler, FLOW_REMOVED_USER_DATA );
  assert_true( event_handlers.flow_removed_callback == mock_simple_flow_removed_handler );
  assert_true( event_handlers.flow_removed_user_data == FLOW_REMOVED_USER_DATA );
}


static void
test_set_flow_removed_handler_if_handler_is_NULL() {
  expect_string( mock_die, format, "Callback function ( flow_removed_handler ) must not be NULL." );
  expect_assert_failure( set_flow_removed_handler( NULL, NULL ) );
  assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) );
}


/********************************************************************************
 * set_port_status_handler() tests.
 ********************************************************************************/

static void
test_set_port_status_handler() {
  assert_true( set_port_status_handler( PORT_STATUS_HANDLER, PORT_STATUS_USER_DATA ) );
  assert_int_equal( event_handlers.port_status_callback, PORT_STATUS_HANDLER );
  assert_int_equal( event_handlers.port_status_user_data, PORT_STATUS_USER_DATA );
}


static void
test_set_port_status_handler_if_handler_is_NULL() {
  expect_string( mock_die, format, "Callback function ( port_status_handler ) must not be NULL." );
  expect_assert_failure( set_port_status_handler( NULL, NULL ) );
  assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) );
}


/********************************************************************************
 * set_multipart_reply_handler() tests.
 ********************************************************************************/

static void
test_set_multipart_reply_handler() {
  assert_true( set_multipart_reply_handler( MULTIPART_REPLY_HANDLER, MULTIPART_REPLY_USER_DATA ) );
  assert_int_equal( event_handlers.multipart_reply_callback, MULTIPART_REPLY_HANDLER );
  assert_int_equal( event_handlers.multipart_reply_user_data, MULTIPART_REPLY_USER_DATA );
}


static void
test_set_multipart_reply_handler_if_handler_is_NULL() {
  expect_string( mock_die, format, "Callback function ( multipart_reply_handler ) must not be NULL." );
  expect_assert_failure( set_multipart_reply_handler( NULL, NULL ) );
  assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) );
}


/********************************************************************************
 * set_barrier_reply_handler() tests.
 ********************************************************************************/

static void
test_set_barrier_reply_handler() {
  assert_true( set_barrier_reply_handler( BARRIER_REPLY_HANDLER, BARRIER_REPLY_USER_DATA ) );
  assert_int_equal( event_handlers.barrier_reply_callback, BARRIER_REPLY_HANDLER );
  assert_int_equal( event_handlers.barrier_reply_user_data, BARRIER_REPLY_USER_DATA );
}


static void
test_set_barrier_reply_handler_if_handler_is_NULL() {
  expect_string( mock_die, format, "Callback function ( barrier_reply_handler ) must not be NULL." );
  expect_assert_failure( set_barrier_reply_handler( NULL, NULL ) );
  assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) );
}


/********************************************************************************
 * set_queue_get_config_reply_handler() tests.
 ********************************************************************************/

static void
test_set_queue_get_config_reply_handler() {
  assert_true( set_queue_get_config_reply_handler( QUEUE_GET_CONFIG_REPLY_HANDLER, QUEUE_GET_CONFIG_REPLY_USER_DATA ) );
  assert_int_equal( event_handlers.queue_get_config_reply_callback, QUEUE_GET_CONFIG_REPLY_HANDLER );
  assert_int_equal( event_handlers.queue_get_config_reply_user_data, QUEUE_GET_CONFIG_REPLY_USER_DATA );
}


static void
test_set_queue_get_config_reply_handler_if_handler_is_NULL() {
  expect_string( mock_die, format, "Callback function ( queue_get_config_reply_handler ) must not be NULL." );
  expect_assert_failure( set_queue_get_config_reply_handler( NULL, NULL ) );
  assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) );
}


/********************************************************************************
 * set_role_reply_handler() tests.
 ********************************************************************************/

static void
test_set_role_reply_handler() {
  assert_true( set_role_reply_handler( ROLE_REPLY_HANDLER, ROLE_REPLY_USER_DATA ) );
  assert_int_equal( event_handlers.role_reply_callback, ROLE_REPLY_HANDLER );
  assert_int_equal( event_handlers.role_reply_user_data, ROLE_REPLY_USER_DATA );
}


static void
test_set_role_reply_handler_if_handler_is_NULL() {
  expect_string( mock_die, format, "Callback function ( role_reply_handler ) must not be NULL." );
  expect_assert_failure( set_role_reply_handler( NULL, NULL ) );
  assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) );
}


/********************************************************************************
 * set_get_async_reply_handler() tests.
 ********************************************************************************/

static void
test_set_get_async_reply_handler() {
  assert_true( set_get_async_reply_handler( GET_ASYNC_REPLY_HANDLER, GET_ASYNC_REPLY_USER_DATA ) );
  assert_int_equal( event_handlers.get_async_reply_callback, GET_ASYNC_REPLY_HANDLER );
  assert_int_equal( event_handlers.get_async_reply_user_data, GET_ASYNC_REPLY_USER_DATA );
}


static void
test_set_get_async_reply_handler_if_handler_is_NULL() {
  expect_string( mock_die, format, "Callback function ( get_async_reply_handler ) must not be NULL." );
  expect_assert_failure( set_get_async_reply_handler( NULL, NULL ) );
  assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) );
}


/********************************************************************************
 * set_list_switches_reply_handler() tests.
 ********************************************************************************/


static void
test_set_list_switches_reply_handler() {
  assert_true( set_list_switches_reply_handler( LIST_SWITCHES_REPLY_HANDLER ) );
  assert_int_equal( event_handlers.list_switches_reply_callback, LIST_SWITCHES_REPLY_HANDLER );
}


static void
test_set_list_switches_reply_handler_if_handler_is_NULL() {
  expect_string( mock_die, format, "Callback function ( list_switches_reply_handler ) must not be NULL." );
  expect_assert_failure( set_list_switches_reply_handler( NULL ) );
  assert_memory_equal( &event_handlers, &NULL_EVENT_HANDLERS, sizeof( event_handlers ) );
}


/********************************************************************************
 * send_openflow_message() tests.
 ********************************************************************************/

static void
test_send_openflow_message() {
  void *expected_data;
  bool ret;
  size_t expected_length, header_length;
  buffer *buffer;
  openflow_service_header_t *header;

  buffer = create_hello( TRANSACTION_ID, NULL );

  assert_true( buffer != NULL );

  header_length = ( size_t ) ( sizeof( openflow_service_header_t ) +
                               strlen( SERVICE_NAME ) + 1 );
  expected_length = ( size_t ) ( header_length + sizeof( struct ofp_header ) );

  expected_data = xcalloc( 1, expected_length );

  header = expected_data;
  header->datapath_id = htonll( DATAPATH_ID );
  header->service_name_length = htons( ( uint16_t ) ( strlen( SERVICE_NAME ) + 1 ) );

  memcpy( ( char * ) expected_data + sizeof( openflow_service_header_t ),
          SERVICE_NAME, strlen( SERVICE_NAME ) + 1 );
  memcpy( ( char * ) expected_data + header_length, buffer->data, buffer->length );

  expect_string( mock_send_message, service_name, REMOTE_SERVICE_NAME );
  expect_value( mock_send_message, tag32, MESSENGER_OPENFLOW_MESSAGE );
  expect_value( mock_send_message, len, expected_length );
  expect_memory( mock_send_message, data, expected_data, expected_length );
  will_return( mock_send_message, true );

  ret = send_openflow_message( DATAPATH_ID, buffer );
  
  assert_true( ret );
  stat_entry *stat = lookup_hash_entry( stats, "openflow_application_interface.hello_send_succeeded" );
  assert_int_equal( ( int ) stat->value, 1 );

  free_buffer( buffer );
  xfree( expected_data );
  xfree( delete_hash_entry( stats, "openflow_application_interface.hello_send_succeeded" ) );
}


static void
test_send_openflow_message_if_message_is_NULL() {
  expect_assert_failure( send_openflow_message( DATAPATH_ID, NULL ) );
}


static void
test_send_openflow_message_if_message_length_is_zero() {
  buffer *buffer;

  buffer = alloc_buffer_with_length( 128 );

  assert_true( buffer != NULL );

  expect_assert_failure( send_openflow_message( DATAPATH_ID, NULL ) );

  free_buffer( buffer );
}


/********************************************************************************
 * handle_error() tests.
 ********************************************************************************/

static void
test_handle_error() {
  buffer *buffer, *data;

  data = alloc_buffer_with_length( 16 );
  append_back_buffer( data, 16 );
  memset( data->data, 'a', 16 );

  buffer = create_error( TRANSACTION_ID, OFPET_HELLO_FAILED, OFPHFC_INCOMPATIBLE, data );

  expect_memory( mock_error_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_value( mock_error_handler, transaction_id, TRANSACTION_ID );
  expect_value( mock_error_handler, type32, OFPET_HELLO_FAILED );
  expect_value( mock_error_handler, code32, OFPHFC_INCOMPATIBLE );
  expect_value( mock_error_handler, data->length, data->length );
  expect_memory( mock_error_handler, data->data, data->data, data->length );
  expect_memory( mock_error_handler, user_data, USER_DATA, USER_DATA_LEN );

  set_error_handler( mock_error_handler, USER_DATA );
  handle_error( DATAPATH_ID, buffer );

  free_buffer( data );
  free_buffer( buffer );
}


static void
test_handle_error_if_handler_is_not_registered() {
  buffer *buffer, *data;

  data = alloc_buffer_with_length( 16 );
  append_back_buffer( data, 16 );
  memset( data->data, 'a', 16 );

  buffer = create_error( TRANSACTION_ID, OFPET_HELLO_FAILED, OFPHFC_INCOMPATIBLE, data );

  // FIXME

  handle_error( DATAPATH_ID, buffer );

  free_buffer( data );
  free_buffer( buffer );
}


static void
test_handle_error_if_message_is_NULL() {
  set_error_handler( mock_error_handler, USER_DATA );
  expect_assert_failure( handle_error( DATAPATH_ID, NULL ) );
}


static void
test_handle_error_if_message_length_is_zero() {
  buffer *buffer;

  buffer = alloc_buffer_with_length( 32 );

  set_error_handler( mock_error_handler, USER_DATA );
  expect_assert_failure( handle_error( DATAPATH_ID, buffer ) );

  free_buffer( buffer );
}


/********************************************************************************
 * handle_experimenter_error() tests.
 ********************************************************************************/

static void
test_handle_experimenter_error() {
    uint16_t type = OFPET_EXPERIMENTER;

    uint16_t exp_type = 0x3344;
    uint32_t experimenter = 0x55667788;
    buffer *buffer, *data;
    
    data = alloc_buffer_with_length( 16 );
    append_back_buffer( data, 16 );
    memset( data->data, 'a', 16 );

    buffer = create_error_experimenter( TRANSACTION_ID, type, exp_type, experimenter, data );
    
    expect_memory( mock_experimenter_error_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
    expect_value( mock_experimenter_error_handler, transaction_id, TRANSACTION_ID );
    expect_value( mock_experimenter_error_handler, type32, ( uint32_t ) type );
    expect_value( mock_experimenter_error_handler, exp_type32, ( uint32_t ) exp_type );
    expect_value( mock_experimenter_error_handler, experimenter, experimenter );
    expect_value( mock_experimenter_error_handler, data->length, data->length );
    expect_memory( mock_experimenter_error_handler, data->data, data->data, data->length );
    expect_memory( mock_experimenter_error_handler, user_data, USER_DATA, USER_DATA_LEN );

    set_experimenter_error_handler( mock_experimenter_error_handler, USER_DATA );
    handle_experimenter_error( DATAPATH_ID, buffer );

    free_buffer( data );
    free_buffer( buffer );
}


static void
test_handle_experimenter_error_if_handler_is_not_registered() {
    uint16_t type = OFPET_EXPERIMENTER;

    uint16_t exp_type = 0x3344;
    uint32_t experimenter = 0x55667788;
    buffer *buffer, *data;
    
    data = alloc_buffer_with_length( 16 );
    append_back_buffer( data, 16 );
    memset( data->data, 'a', 16 );

    buffer = create_error_experimenter( TRANSACTION_ID, type, exp_type, experimenter, data );

  // FIXME

    handle_experimenter_error( DATAPATH_ID, buffer );

    free_buffer( data );
    free_buffer( buffer );
}


static void
test_handle_experimenter_error_if_message_is_NULL() {
  set_experimenter_error_handler( mock_experimenter_error_handler, USER_DATA );
  expect_assert_failure( handle_experimenter_error( DATAPATH_ID, NULL ) );
}


static void
test_handle_experimenter_error_if_message_length_is_zero() {
  buffer *buffer;

  buffer = alloc_buffer_with_length( 32 );

  set_experimenter_error_handler( mock_experimenter_error_handler, USER_DATA );
  expect_assert_failure( handle_experimenter_error( DATAPATH_ID, buffer ) );

  free_buffer( buffer );
}


/********************************************************************************
 * handle_echo_reply() tests.
 ********************************************************************************/

static void
test_handle_echo_reply() {
  buffer *buffer, *data;

  data = alloc_buffer_with_length( 16 );
  append_back_buffer( data, 16 );
  memset( data->data, 'a', 16 );

  buffer = create_echo_reply( TRANSACTION_ID, data );

  expect_memory( mock_echo_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_value( mock_echo_reply_handler, transaction_id, TRANSACTION_ID );
  expect_value( mock_echo_reply_handler, data->length, data->length );
  expect_memory( mock_echo_reply_handler, data->data, data->data, data->length );
  expect_memory( mock_echo_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

  set_echo_reply_handler( mock_echo_reply_handler, USER_DATA );
  handle_echo_reply( DATAPATH_ID, buffer );

  free_buffer( data );
  free_buffer( buffer );
}


static void
test_handle_echo_reply_without_data() {
  buffer *buffer;

  buffer = create_echo_reply( TRANSACTION_ID, NULL );

  expect_memory( mock_echo_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_value( mock_echo_reply_handler, transaction_id, TRANSACTION_ID );
  expect_value( mock_echo_reply_handler, data_uc, NULL );
  expect_memory( mock_echo_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

  set_echo_reply_handler( mock_echo_reply_handler, USER_DATA );
  handle_echo_reply( DATAPATH_ID, buffer );

  free_buffer( buffer );
}


static void
test_handle_echo_reply_if_handler_is_not_registered() {
  buffer *buffer, *data;

  data = alloc_buffer_with_length( 16 );
  append_back_buffer( data, 16 );
  memset( data->data, 'a', 16 );

  buffer = create_echo_reply( TRANSACTION_ID, data );

  // FIXME

  handle_echo_reply( DATAPATH_ID, buffer );

  free_buffer( data );
  free_buffer( buffer );
}


static void
test_handle_echo_reply_if_message_is_NULL() {
  set_echo_reply_handler( mock_echo_reply_handler, USER_DATA );
  expect_assert_failure( handle_echo_reply( DATAPATH_ID, NULL ) );
}


static void
test_handle_echo_reply_if_message_length_is_zero() {
  buffer *buffer;

  buffer = alloc_buffer_with_length( 32 );

  set_echo_reply_handler( mock_echo_reply_handler, USER_DATA );
  expect_assert_failure( handle_echo_reply( DATAPATH_ID, buffer ) );

  free_buffer( buffer );
}


/********************************************************************************
 * handle_experimenter() tests.
 ********************************************************************************/

static void
test_handle_experimenter() {
  buffer *buffer, *data;
  uint32_t exp_type = 0x1122;

  data = alloc_buffer_with_length( 16 );
  append_back_buffer( data, 16 );
  memset( data->data, 'a', 16 );

  buffer = create_experimenter( TRANSACTION_ID, VENDOR_ID, exp_type, data );

  expect_memory( mock_experimenter_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_value( mock_experimenter_handler, transaction_id, TRANSACTION_ID );
  expect_value( mock_experimenter_handler, experimenter, VENDOR_ID );
  expect_value( mock_experimenter_handler, exp_type, exp_type );
  expect_value( mock_experimenter_handler, data->length, data->length );
  expect_memory( mock_experimenter_handler, data->data, data->data, data->length );
  expect_memory( mock_experimenter_handler, user_data, USER_DATA, USER_DATA_LEN );

  set_experimenter_handler( mock_experimenter_handler, USER_DATA );
  handle_experimenter( DATAPATH_ID, buffer );

  free_buffer( data );
  free_buffer( buffer );
}


static void
test_handle_experimenter_without_data() {
  buffer *buffer, *data;
  uint32_t exp_type = 0x1122;

  data = alloc_buffer_with_length( 16 );
  append_back_buffer( data, 16 );
  memset( data->data, 'a', 16 );

  buffer = create_experimenter( TRANSACTION_ID, VENDOR_ID, exp_type, NULL );

  expect_memory( mock_experimenter_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_value( mock_experimenter_handler, transaction_id, TRANSACTION_ID );
  expect_value( mock_experimenter_handler, experimenter, VENDOR_ID );
  expect_value( mock_experimenter_handler, exp_type, exp_type );
  expect_value( mock_experimenter_handler, data_uc, NULL );
  expect_memory( mock_experimenter_handler, user_data, USER_DATA, USER_DATA_LEN );

  set_experimenter_handler( mock_experimenter_handler, USER_DATA );
  handle_experimenter( DATAPATH_ID, buffer );

  free_buffer( data );
  free_buffer( buffer );
}


static void
test_handle_experimenter_if_handler_is_not_registered() {
  buffer *buffer, *data;
  uint32_t exp_type = 0x1122;

  data = alloc_buffer_with_length( 16 );
  append_back_buffer( data, 16 );
  memset( data->data, 'a', 16 );

  buffer = create_experimenter( TRANSACTION_ID, VENDOR_ID, exp_type, data );

  // FIXME

  handle_experimenter( DATAPATH_ID, buffer );

  free_buffer( data );
  free_buffer( buffer );
}


static void
test_handle_experimenter_if_message_is_NULL() {
  set_experimenter_handler( mock_experimenter_handler, USER_DATA );
  expect_assert_failure( handle_experimenter( DATAPATH_ID, NULL ) );
}


static void
test_handle_experimenter_if_message_length_is_zero() {
  buffer *buffer;

  buffer = alloc_buffer_with_length( 32 );

  set_experimenter_handler( mock_experimenter_handler, USER_DATA );
  expect_assert_failure( handle_experimenter( DATAPATH_ID, buffer ) );

  free_buffer( buffer );
}


/********************************************************************************
 * handle_features_reply() tests.
 ********************************************************************************/

static void
test_handle_features_reply() {
  uint32_t n_buffers = 1024;
  uint8_t n_tables = 2;
  uint8_t auxiliary_id = 0x11;
  uint32_t capabilities;
  buffer *buffer;

  capabilities = ( OFPC_FLOW_STATS | OFPC_TABLE_STATS | OFPC_PORT_STATS |
                   OFPC_GROUP_STATS | OFPC_IP_REASM | OFPC_QUEUE_STATS | OFPC_PORT_BLOCKED );

  buffer = create_features_reply( TRANSACTION_ID, DATAPATH_ID, n_buffers, n_tables,
                                  auxiliary_id, capabilities );

  expect_memory( mock_features_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_value( mock_features_reply_handler, transaction_id, TRANSACTION_ID );
  expect_value( mock_features_reply_handler, n_buffers, n_buffers );
  expect_value( mock_features_reply_handler, n_tables32, ( uint32_t ) n_tables );
  expect_value( mock_features_reply_handler, auxiliary_id32, ( uint32_t ) auxiliary_id );
  expect_value( mock_features_reply_handler, capabilities, capabilities );
  expect_memory( mock_features_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

  set_features_reply_handler( mock_features_reply_handler, USER_DATA );
  handle_features_reply( DATAPATH_ID, buffer );

  free_buffer( buffer );
}


static void
test_handle_features_reply_if_handler_is_not_registered() {
  uint32_t n_buffers = 1024;
  uint8_t n_tables = 2;
  uint8_t auxiliary_id = 0x11;
  uint32_t capabilities;
  buffer *buffer;

  capabilities = ( OFPC_FLOW_STATS | OFPC_TABLE_STATS | OFPC_PORT_STATS |
                   OFPC_GROUP_STATS | OFPC_IP_REASM | OFPC_QUEUE_STATS | OFPC_PORT_BLOCKED );

  buffer = create_features_reply( TRANSACTION_ID, DATAPATH_ID, n_buffers, n_tables,
                                  auxiliary_id, capabilities );

  // FIXME

  handle_features_reply( DATAPATH_ID, buffer );

  free_buffer( buffer );
}


static void
test_handle_features_reply_if_message_is_NULL() {
  set_features_reply_handler( mock_features_reply_handler, USER_DATA );
  expect_assert_failure( handle_features_reply( DATAPATH_ID, NULL ) );
}


static void
test_handle_features_reply_if_message_length_is_zero() {
  buffer *buffer;

  buffer = alloc_buffer_with_length( 32 );

  set_features_reply_handler( mock_features_reply_handler, USER_DATA );
  expect_assert_failure( handle_features_reply( DATAPATH_ID, buffer ) );

  free_buffer( buffer );
}


/********************************************************************************
 * handle_get_config_reply() tests.
 ********************************************************************************/

static void
test_handle_get_config_reply() {
  uint16_t flags = OFPC_FRAG_NORMAL;
  uint16_t miss_send_len = 128;
  buffer *buffer;

  buffer = create_get_config_reply( TRANSACTION_ID, flags, miss_send_len );

  expect_memory( mock_get_config_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_value( mock_get_config_reply_handler, transaction_id, TRANSACTION_ID );
  expect_value( mock_get_config_reply_handler, flags32, ( uint32_t ) flags );
  expect_value( mock_get_config_reply_handler, miss_send_len32, ( uint32_t ) miss_send_len );
  expect_memory( mock_get_config_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

  set_get_config_reply_handler( mock_get_config_reply_handler, USER_DATA );
  handle_get_config_reply( DATAPATH_ID, buffer );

  free_buffer( buffer );
}


static void
test_handle_get_config_reply_if_handler_is_not_registered() {
  uint16_t flags = OFPC_FRAG_NORMAL;
  uint16_t miss_send_len = 128;
  buffer *buffer;

  buffer = create_get_config_reply( TRANSACTION_ID, flags, miss_send_len );

  // FIXME

  handle_get_config_reply( DATAPATH_ID, buffer );

  free_buffer( buffer );
}


static void
test_handle_get_config_reply_if_message_is_NULL() {
  set_get_config_reply_handler( mock_get_config_reply_handler, USER_DATA );
  expect_assert_failure( handle_get_config_reply( DATAPATH_ID, NULL ) );
}


static void
test_handle_get_config_reply_if_message_length_is_zero() {
  buffer *buffer;

  buffer = alloc_buffer_with_length( 32 );

  set_get_config_reply_handler( mock_get_config_reply_handler, USER_DATA );
  expect_assert_failure( handle_get_config_reply( DATAPATH_ID, buffer ) );

  free_buffer( buffer );
}


/********************************************************************************
 * handle_packet_in() tests.
 ********************************************************************************/
static void
test_handle_packet_in() {
  uint32_t buffer_id = 0x01020304;
  uint8_t reason = OFPR_NO_MATCH;
  uint8_t table_id = 0x01;
  uint64_t cookie = 0xAAAABBBBCCCCDDDD;
  oxm_matches *match;
  size_t match1_len, match2_len;
  oxm_match_header *queue[ 2 ];
  uint32_t* value;
  
  match1_len = ( sizeof( oxm_match_header ) + OXM_LENGTH( OXM_OF_IN_PORT ) );
  queue[ 0 ] = xcalloc( 1, match1_len );
  value = ( uint32_t* ) (queue[ 0 ] + 1);
  *queue[ 0 ] = OXM_OF_IN_PORT;
  *value = 0x2468ACEF;
    
  match2_len = ( sizeof( oxm_match_header ) + OXM_LENGTH( OXM_OF_IN_PHY_PORT ) );
  queue[ 1 ] = xcalloc( 1, match2_len );
  value = ( uint32_t* ) (queue[ 1 ] + 1);
  *queue[ 1 ] = OXM_OF_IN_PHY_PORT;
  *value = 0xFECA8642;

  match = create_oxm_matches();
  match->n_matches = 2;
  append_to_tail( &match->list, queue[ 0 ] );
  append_to_tail( &match->list, queue[ 1 ] );

  buffer *data = alloc_buffer_with_length( 64 );
  calloc_packet_info( data );
  append_back_buffer( data, 64 );
  memset( data->data, 0x01, 64 );
  uint16_t total_len = ( uint16_t ) data->length ;


  buffer *buffer = create_packet_in( TRANSACTION_ID, buffer_id, total_len, reason, table_id, cookie, match, data );
  
  will_return( mock_parse_packet, true );
  expect_memory( mock_packet_in_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_value( mock_packet_in_handler, transaction_id, TRANSACTION_ID );
  expect_value( mock_packet_in_handler, buffer_id, buffer_id );
  expect_value( mock_packet_in_handler, total_len32, ( uint32_t ) total_len );
  expect_value( mock_packet_in_handler, reason32, ( uint32_t ) reason );
  expect_value( mock_packet_in_handler, table_id32, ( uint32_t ) table_id );
  expect_memory( mock_packet_in_handler, &cookie, &cookie, sizeof( uint64_t ) );
  expect_memory( mock_packet_in_handler, match1, queue[ 0 ], match1_len );
  expect_memory( mock_packet_in_handler, match2, queue[ 1 ], match2_len );
  expect_value( mock_packet_in_handler, data->length, data->length );
  expect_memory( mock_packet_in_handler, data->data, data->data, data->length );
  expect_memory( mock_packet_in_handler, user_data, USER_DATA, USER_DATA_LEN );

  set_packet_in_handler( mock_packet_in_handler, USER_DATA );
  handle_packet_in( DATAPATH_ID, buffer );

  delete_oxm_matches(match);
  free_buffer( buffer );
  free_buffer( data );
}


static void
test_handle_packet_in_with_simple_handler() {
  uint32_t buffer_id = 0x01020304;
  uint8_t reason = OFPR_NO_MATCH;
  uint8_t table_id = 0x01;
  uint64_t cookie = 0xAAAABBBBCCCCDDDD;
  oxm_matches *match;
  size_t match1_len, match2_len;
  oxm_match_header *queue[ 2 ];
  uint32_t* value;
  
  match1_len = ( sizeof( oxm_match_header ) + OXM_LENGTH( OXM_OF_IN_PORT ) );
  queue[ 0 ] = xcalloc( 1, match1_len );
  value = ( uint32_t* ) (queue[ 0 ] + 1);
  *queue[ 0 ] = OXM_OF_IN_PORT;
  *value = 0x2468ACEF;
    
  match2_len = ( sizeof( oxm_match_header ) + OXM_LENGTH( OXM_OF_IN_PHY_PORT ) );
  queue[ 1 ] = xcalloc( 1, match2_len );
  value = ( uint32_t* ) (queue[ 1 ] + 1);
  *queue[ 1 ] = OXM_OF_IN_PHY_PORT;
  *value = 0xFECA8642;

  match = create_oxm_matches();
  match->n_matches = 2;
  append_to_tail( &match->list, queue[ 0 ] );
  append_to_tail( &match->list, queue[ 1 ] );

  buffer *data = alloc_buffer_with_length( 64 );
  calloc_packet_info( data );
  append_back_buffer( data, 64 );
  memset( data->data, 0x01, 64 );
  uint16_t total_len = ( uint16_t ) data->length ;

  buffer *buffer = create_packet_in( TRANSACTION_ID, buffer_id, total_len, reason, table_id, cookie, match, data );
  
  will_return( mock_parse_packet, true );
  expect_memory( mock_simple_packet_in_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_value( mock_simple_packet_in_handler, transaction_id, TRANSACTION_ID );
  expect_value( mock_simple_packet_in_handler, buffer_id, buffer_id );
  expect_value( mock_simple_packet_in_handler, total_len32, ( uint32_t ) total_len );
  expect_value( mock_simple_packet_in_handler, reason32, ( uint32_t ) reason );
  expect_value( mock_simple_packet_in_handler, table_id32, ( uint32_t ) table_id );
  expect_memory( mock_simple_packet_in_handler, &cookie, &cookie, sizeof( uint64_t ) );
  expect_memory( mock_simple_packet_in_handler, match1, queue[ 0 ], match1_len );
  expect_memory( mock_simple_packet_in_handler, match2, queue[ 1 ], match2_len );
  expect_value( mock_simple_packet_in_handler, data->length, data->length );
  expect_memory( mock_simple_packet_in_handler, user_data, USER_DATA, USER_DATA_LEN );

  set_packet_in_handler( mock_simple_packet_in_handler, USER_DATA );
  handle_packet_in( DATAPATH_ID, buffer );

  delete_oxm_matches(match);
  free_buffer( buffer );
  free_buffer( data );
}


static void
test_handle_packet_in_with_malformed_packet() {
  uint32_t buffer_id = 0x01020304;
  uint8_t reason = OFPR_NO_MATCH;
  uint8_t table_id = 0x01;
  uint64_t cookie = 0xAAAABBBBCCCCDDDD;
  oxm_matches *match;
  size_t match1_len, match2_len;
  oxm_match_header *queue[ 2 ];
  uint32_t* value;
  
  match1_len = ( sizeof( oxm_match_header ) + OXM_LENGTH( OXM_OF_IN_PORT ) );
  queue[ 0 ] = xcalloc( 1, match1_len );
  value = ( uint32_t* ) (queue[ 0 ] + 1);
  *queue[ 0 ] = OXM_OF_IN_PORT;
  *value = 0x2468ACEF;
    
  match2_len = ( sizeof( oxm_match_header ) + OXM_LENGTH( OXM_OF_IN_PHY_PORT ) );
  queue[ 1 ] = xcalloc( 1, match2_len );
  value = ( uint32_t* ) (queue[ 1 ] + 1);
  *queue[ 1 ] = OXM_OF_IN_PHY_PORT;
  *value = 0xFECA8642;

  match = create_oxm_matches();
  match->n_matches = 2;
  append_to_tail( &match->list, queue[ 0 ] );
  append_to_tail( &match->list, queue[ 1 ] );

  buffer *data = alloc_buffer_with_length( 64 );
  calloc_packet_info( data );
  append_back_buffer( data, 64 );
  memset( data->data, 0x01, 64 );
  uint16_t total_len = ( uint16_t ) data->length ;

  buffer *buffer = create_packet_in( TRANSACTION_ID, buffer_id, total_len, reason, table_id, cookie, match, data );

  will_return( mock_parse_packet, false );

  set_packet_in_handler( mock_packet_in_handler, USER_DATA );

  handle_packet_in( DATAPATH_ID, buffer );

  assert_false( packet_in_handler_called );

  delete_oxm_matches(match);
  free_buffer( buffer );
  free_buffer( data );
}


static void
test_handle_packet_in_without_data() {
  uint32_t buffer_id = 0x01020304;
  uint8_t reason = OFPR_NO_MATCH;
  uint8_t table_id = 0x01;
  uint64_t cookie = 0xAAAABBBBCCCCDDDD;
  oxm_matches *match;
  size_t match1_len, match2_len;
  oxm_match_header *queue[ 2 ];
  uint32_t* value;
  
  match1_len = ( sizeof( oxm_match_header ) + OXM_LENGTH( OXM_OF_IN_PORT ) );
  queue[ 0 ] = xcalloc( 1, match1_len );
  value = ( uint32_t* ) (queue[ 0 ] + 1);
  *queue[ 0 ] = OXM_OF_IN_PORT;
  *value = 0x2468ACEF;
    
  match2_len = ( sizeof( oxm_match_header ) + OXM_LENGTH( OXM_OF_IN_PHY_PORT ) );
  queue[ 1 ] = xcalloc( 1, match2_len );
  value = ( uint32_t* ) (queue[ 1 ] + 1);
  *queue[ 1 ] = OXM_OF_IN_PHY_PORT;
  *value = 0xFECA8642;

  match = create_oxm_matches();
  match->n_matches = 2;
  append_to_tail( &match->list, queue[ 0 ] );
  append_to_tail( &match->list, queue[ 1 ] );

  buffer *data = alloc_buffer_with_length( 64 );
  append_back_buffer( data, 64 );
  memset( data->data, 0x01, 64 );
  uint16_t total_len = ( uint16_t ) data->length ;

  buffer *buffer = create_packet_in( TRANSACTION_ID, buffer_id, total_len, reason, table_id, cookie, match, NULL );
  
  expect_memory( mock_packet_in_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_value( mock_packet_in_handler, transaction_id, TRANSACTION_ID );
  expect_value( mock_packet_in_handler, buffer_id, buffer_id );
  expect_value( mock_packet_in_handler, total_len32, ( uint32_t ) total_len );
  expect_value( mock_packet_in_handler, reason32, ( uint32_t ) reason );
  expect_value( mock_packet_in_handler, table_id32, ( uint32_t ) table_id );
  expect_memory( mock_packet_in_handler, &cookie, &cookie, sizeof( uint64_t ) );
  expect_memory( mock_packet_in_handler, match1, queue[ 0 ], match1_len );
  expect_memory( mock_packet_in_handler, match2, queue[ 1 ], match2_len );
  expect_value( mock_packet_in_handler, data_uc, NULL );
  expect_memory( mock_packet_in_handler, user_data, USER_DATA, USER_DATA_LEN );

  set_packet_in_handler( mock_packet_in_handler, USER_DATA );
  handle_packet_in( DATAPATH_ID, buffer );

  delete_oxm_matches(match);
  free_buffer( data );
  free_buffer( buffer );
}


static void
test_handle_packet_in_without_handler() {
  uint32_t buffer_id = 0x01020304;
  uint8_t reason = OFPR_NO_MATCH;
  uint8_t table_id = 0x01;
  uint64_t cookie = 0xAAAABBBBCCCCDDDD;
  oxm_matches *match;
  size_t match1_len, match2_len;
  oxm_match_header *queue[ 2 ];
  uint32_t* value;
  
  match1_len = ( sizeof( oxm_match_header ) + OXM_LENGTH( OXM_OF_IN_PORT ) );
  queue[ 0 ] = xcalloc( 1, match1_len );
  value = ( uint32_t* ) (queue[ 0 ] + 1);
  *queue[ 0 ] = OXM_OF_IN_PORT;
  *value = 0x2468ACEF;
    
  match2_len = ( sizeof( oxm_match_header ) + OXM_LENGTH( OXM_OF_IN_PHY_PORT ) );
  queue[ 1 ] = xcalloc( 1, match2_len );
  value = ( uint32_t* ) (queue[ 1 ] + 1);
  *queue[ 1 ] = OXM_OF_IN_PHY_PORT;
  *value = 0xFECA8642;

  match = create_oxm_matches();
  match->n_matches = 2;
  append_to_tail( &match->list, queue[ 0 ] );
  append_to_tail( &match->list, queue[ 1 ] );

  buffer *data = alloc_buffer_with_length( 64 );
  append_back_buffer( data, 64 );
  memset( data->data, 0x01, 64 );
  uint16_t total_len = ( uint16_t ) data->length ;

  buffer *buffer = create_packet_in( TRANSACTION_ID, buffer_id, total_len, reason, table_id, cookie, match, data );
  handle_packet_in( DATAPATH_ID, buffer );
  assert_false( packet_in_handler_called );

  free_buffer( data );
  delete_oxm_matches(match);
  free_buffer( buffer );
}


static void
test_handle_packet_in_should_die_if_message_is_NULL() {
  expect_string( mock_die, format, "handle_packet_in(): packet_in message should not be empty." );
  set_packet_in_handler( mock_packet_in_handler, USER_DATA );
  expect_assert_failure( handle_packet_in( DATAPATH_ID, NULL ) );
}


static void
test_handle_packet_in_should_die_if_message_length_is_zero() {
  buffer *buffer = alloc_buffer_with_length( 32 );

  expect_string( mock_die, format, "handle_packet_in(): packet_in message should not be empty." );
  set_packet_in_handler( mock_packet_in_handler, USER_DATA );
  expect_assert_failure( handle_packet_in( DATAPATH_ID, buffer ) );

  free_buffer( buffer );
}


/********************************************************************************
 * handle_flow_removed() tests.
 ********************************************************************************/

static void
test_handle_flow_removed() {
  uint64_t cookie = 0x1111222233334444;
  uint16_t priority = OFP_HIGH_PRIORITY;
  uint8_t reason =  OFPRR_IDLE_TIMEOUT;
  uint8_t table_id = 0xAA;
  uint32_t duration_sec = 180;
  uint32_t duration_nsec = 10000;
  uint16_t idle_timeout = 60;
  uint16_t hard_timeout = 120;
  uint64_t packet_count = 1000;
  uint64_t byte_count = 100000;
  oxm_matches *match;
  size_t match1_len, match2_len;
  oxm_match_header *queue[ 2 ];
  uint32_t* value;
  
  match1_len = ( sizeof( oxm_match_header ) + OXM_LENGTH( OXM_OF_IN_PORT ) );
  queue[ 0 ] = xcalloc( 1, match1_len );
  value = ( uint32_t* ) (queue[ 0 ] + 1);
  *queue[ 0 ] = OXM_OF_IN_PORT;
  *value = 0x2468ACEF;
    
  match2_len = ( sizeof( oxm_match_header ) + OXM_LENGTH( OXM_OF_IN_PHY_PORT ) );
  queue[ 1 ] = xcalloc( 1, match2_len );
  value = ( uint32_t* ) (queue[ 1 ] + 1);
  *queue[ 1 ] = OXM_OF_IN_PHY_PORT;
  *value = 0xFECA8642;

  match = create_oxm_matches();
  match->n_matches = 2;
  append_to_tail( &match->list, queue[ 0 ] );
  append_to_tail( &match->list, queue[ 1 ] );

  buffer *buffer = create_flow_removed(
    TRANSACTION_ID,
    cookie,
    priority,
    reason,
    table_id,
    duration_sec,
    duration_nsec,
    idle_timeout,
    hard_timeout,
    packet_count,
    byte_count,
    match
  );

  expect_memory( mock_flow_removed_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_value( mock_flow_removed_handler, transaction_id, TRANSACTION_ID );
  expect_memory( mock_flow_removed_handler, &cookie, &cookie, sizeof( uint64_t ) );
  expect_value( mock_flow_removed_handler, priority32, ( uint32_t ) priority );
  expect_value( mock_flow_removed_handler, reason32, ( uint32_t ) reason );
  expect_value( mock_flow_removed_handler, table_id32, ( uint32_t ) table_id );
  expect_value( mock_flow_removed_handler, duration_sec, duration_sec );
  expect_value( mock_flow_removed_handler, duration_nsec, duration_nsec );
  expect_value( mock_flow_removed_handler, idle_timeout32, ( uint32_t ) idle_timeout );
  expect_value( mock_flow_removed_handler, hard_timeout32, ( uint32_t ) hard_timeout );
  expect_memory( mock_flow_removed_handler, &packet_count, &packet_count, sizeof( uint64_t ) );
  expect_memory( mock_flow_removed_handler, &byte_count, &byte_count, sizeof( uint64_t ) );
  expect_memory( mock_flow_removed_handler, match1, queue[ 0 ], match1_len );
  expect_memory( mock_flow_removed_handler, match2, queue[ 1 ], match2_len );
  expect_memory( mock_flow_removed_handler, user_data, USER_DATA, USER_DATA_LEN );

  set_flow_removed_handler( mock_flow_removed_handler, USER_DATA );
  handle_flow_removed( DATAPATH_ID, buffer );

  delete_oxm_matches(match);
  free_buffer( buffer );
}


static void
test_handle_flow_removed_with_simple_handler() {
  uint64_t cookie = 0x1111222233334444;
  uint16_t priority = OFP_HIGH_PRIORITY;
  uint8_t reason =  OFPRR_IDLE_TIMEOUT;
  uint8_t table_id = 0xAA;
  uint32_t duration_sec = 180;
  uint32_t duration_nsec = 10000;
  uint16_t idle_timeout = 60;
  uint16_t hard_timeout = 120;
  uint64_t packet_count = 1000;
  uint64_t byte_count = 100000;
  oxm_matches *match;
  size_t match1_len, match2_len;
  oxm_match_header *queue[ 2 ];
  uint32_t* value;
  
  match1_len = ( sizeof( oxm_match_header ) + OXM_LENGTH( OXM_OF_IN_PORT ) );
  queue[ 0 ] = xcalloc( 1, match1_len );
  value = ( uint32_t* ) (queue[ 0 ] + 1);
  *queue[ 0 ] = OXM_OF_IN_PORT;
  *value = 0x2468ACEF;
    
  match2_len = ( sizeof( oxm_match_header ) + OXM_LENGTH( OXM_OF_IN_PHY_PORT ) );
  queue[ 1 ] = xcalloc( 1, match2_len );
  value = ( uint32_t* ) (queue[ 1 ] + 1);
  *queue[ 1 ] = OXM_OF_IN_PHY_PORT;
  *value = 0xFECA8642;

  match = create_oxm_matches();
  match->n_matches = 2;
  append_to_tail( &match->list, queue[ 0 ] );
  append_to_tail( &match->list, queue[ 1 ] );

  buffer *buffer = create_flow_removed(
    TRANSACTION_ID,
    cookie,
    priority,
    reason,
    table_id,
    duration_sec,
    duration_nsec,
    idle_timeout,
    hard_timeout,
    packet_count,
    byte_count,
    match
  );

  expect_memory( mock_simple_flow_removed_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_value( mock_simple_flow_removed_handler, transaction_id, TRANSACTION_ID );
  expect_memory( mock_simple_flow_removed_handler, &cookie, &cookie, sizeof( uint64_t ) );
  expect_value( mock_simple_flow_removed_handler, priority32, ( uint32_t ) priority );
  expect_value( mock_simple_flow_removed_handler, reason32, ( uint32_t ) reason );
  expect_value( mock_simple_flow_removed_handler, table_id32, ( uint32_t ) table_id );
  expect_value( mock_simple_flow_removed_handler, duration_sec, duration_sec );
  expect_value( mock_simple_flow_removed_handler, duration_nsec, duration_nsec );
  expect_value( mock_simple_flow_removed_handler, idle_timeout32, ( uint32_t ) idle_timeout );
  expect_value( mock_simple_flow_removed_handler, hard_timeout32, ( uint32_t ) hard_timeout );
  expect_memory( mock_simple_flow_removed_handler, &packet_count, &packet_count, sizeof( uint64_t ) );
  expect_memory( mock_simple_flow_removed_handler, &byte_count, &byte_count, sizeof( uint64_t ) );
  expect_memory( mock_simple_flow_removed_handler, match1, queue[ 0 ], match1_len );
  expect_memory( mock_simple_flow_removed_handler, match2, queue[ 1 ], match2_len );
  expect_memory( mock_simple_flow_removed_handler, user_data, USER_DATA, USER_DATA_LEN );

  set_flow_removed_handler( mock_simple_flow_removed_handler, USER_DATA );
  handle_flow_removed( DATAPATH_ID, buffer );

  delete_oxm_matches(match);
  free_buffer( buffer );
}


static void
test_handle_flow_removed_if_handler_is_not_registered() {
  uint64_t cookie = 0x1111222233334444;
  uint16_t priority = OFP_HIGH_PRIORITY;
  uint8_t reason =  OFPRR_IDLE_TIMEOUT;
  uint8_t table_id = 0xAA;
  uint32_t duration_sec = 180;
  uint32_t duration_nsec = 10000;
  uint16_t idle_timeout = 60;
  uint16_t hard_timeout = 120;
  uint64_t packet_count = 1000;
  uint64_t byte_count = 100000;
  oxm_matches *match;
  size_t match1_len, match2_len;
  oxm_match_header *queue[ 2 ];
  uint32_t* value;
  
  match1_len = ( sizeof( oxm_match_header ) + OXM_LENGTH( OXM_OF_IN_PORT ) );
  queue[ 0 ] = xcalloc( 1, match1_len );
  value = ( uint32_t* ) (queue[ 0 ] + 1);
  *queue[ 0 ] = OXM_OF_IN_PORT;
  *value = 0x2468ACEF;
    
  match2_len = ( sizeof( oxm_match_header ) + OXM_LENGTH( OXM_OF_IN_PHY_PORT ) );
  queue[ 1 ] = xcalloc( 1, match2_len );
  value = ( uint32_t* ) (queue[ 1 ] + 1);
  *queue[ 1 ] = OXM_OF_IN_PHY_PORT;
  *value = 0xFECA8642;

  match = create_oxm_matches();
  match->n_matches = 2;
  append_to_tail( &match->list, queue[ 0 ] );
  append_to_tail( &match->list, queue[ 1 ] );

  buffer *buffer;
  buffer = create_flow_removed(
    TRANSACTION_ID,
    cookie,
    priority,
    reason,
    table_id,
    duration_sec,
    duration_nsec,
    idle_timeout,
    hard_timeout,
    packet_count,
    byte_count,
    match
  );

  // FIXME
  handle_flow_removed( DATAPATH_ID, buffer );

  delete_oxm_matches(match);
  free_buffer( buffer );
}


static void
test_handle_flow_removed_if_message_is_NULL() {
  set_flow_removed_handler( mock_flow_removed_handler, USER_DATA );
  expect_assert_failure( handle_flow_removed( DATAPATH_ID, NULL ) );
}


static void
test_handle_flow_removed_if_message_length_is_zero() {
  buffer *buffer;

  buffer = alloc_buffer_with_length( 32 );

  set_flow_removed_handler( mock_flow_removed_handler, USER_DATA );
  expect_assert_failure( handle_flow_removed( DATAPATH_ID, buffer ) );

  free_buffer( buffer );
}


/********************************************************************************
 * handle_port_status() tests.
 ********************************************************************************/

static void
test_handle_port_status() {
  uint8_t reason = OFPPR_MODIFY;
  buffer *buffer;
  struct ofp_port desc;

  desc.port_no = 1;
  memset( desc.pad, 0, sizeof( desc.pad ) );
  memcpy( desc.hw_addr, MAC_ADDR_X, sizeof( desc.hw_addr ) );
  memset( desc.pad2, 0, sizeof( desc.pad2 ) );
  memset( desc.name, '\0', OFP_MAX_PORT_NAME_LEN );
  memcpy( desc.name, PORT_NAME, strlen( PORT_NAME ) );
  desc.config = OFPPC_PORT_DOWN;
  desc.state = OFPPS_LINK_DOWN;
  desc.curr = ( OFPPF_1GB_FD | OFPPF_COPPER | OFPPF_PAUSE );
  desc.advertised = PORT_FEATURES;
  desc.supported = PORT_FEATURES;
  desc.peer = PORT_FEATURES;
  desc.curr_speed = 0x1024;
  desc.max_speed = 0x2048;

  buffer = create_port_status( TRANSACTION_ID, reason, desc );

  expect_memory( mock_port_status_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_value( mock_port_status_handler, transaction_id, TRANSACTION_ID );
  expect_value( mock_port_status_handler, reason32, ( uint32_t ) reason );
  expect_memory( mock_port_status_handler, &desc, &desc, sizeof( struct ofp_port ) );
  expect_memory( mock_port_status_handler, user_data, USER_DATA, USER_DATA_LEN );

  set_port_status_handler( mock_port_status_handler, USER_DATA );
  handle_port_status( DATAPATH_ID, buffer );

  free_buffer( buffer );
}


static void
test_handle_port_status_if_handler_is_not_registered() {
  uint8_t reason = OFPPR_MODIFY;
  buffer *buffer;
  struct ofp_port desc;

  desc.port_no = 1;
  memset( desc.pad, 0, sizeof( desc.pad ) );
  memcpy( desc.hw_addr, MAC_ADDR_X, sizeof( desc.hw_addr ) );
  memset( desc.pad2, 0, sizeof( desc.pad2 ) );
  memset( desc.name, '\0', OFP_MAX_PORT_NAME_LEN );
  memcpy( desc.name, PORT_NAME, strlen( PORT_NAME ) );
  desc.config = OFPPC_PORT_DOWN;
  desc.state = OFPPS_LINK_DOWN;
  desc.curr = ( OFPPF_1GB_FD | OFPPF_COPPER | OFPPF_PAUSE );
  desc.advertised = PORT_FEATURES;
  desc.supported = PORT_FEATURES;
  desc.peer = PORT_FEATURES;
  desc.curr_speed = 0x1024;
  desc.max_speed = 0x2048;

  buffer = create_port_status( TRANSACTION_ID, reason, desc );

  // FIXME

  handle_port_status( DATAPATH_ID, buffer );

  free_buffer( buffer );
}


static void
test_handle_port_status_if_message_is_NULL() {
  set_port_status_handler( mock_port_status_handler, USER_DATA );
  expect_assert_failure( handle_port_status( DATAPATH_ID, NULL ) );
}


static void
test_handle_port_status_if_message_length_is_zero() {
  buffer *buffer;

  buffer = alloc_buffer_with_length( 32 );

  set_port_status_handler( mock_port_status_handler, USER_DATA );
  expect_assert_failure( handle_port_status( DATAPATH_ID, buffer ) );

  free_buffer( buffer );
}


/********************************************************************************
 * handle_multipart_reply() tests.
 ********************************************************************************/

static void
test_handle_multipart_reply_if_type_is_OFPMP_DESC() {
  char mfr_desc[ DESC_STR_LEN ];
  char hw_desc[ DESC_STR_LEN ];
  char sw_desc[ DESC_STR_LEN ];
  char serial_num[ SERIAL_NUM_LEN ];
  char dp_desc[ DESC_STR_LEN ];
  uint16_t flags = 0;
  uint32_t body_len;
  buffer *buffer;
  struct ofp_multipart_reply *multipart_reply;

  memset( mfr_desc, '\0', DESC_STR_LEN );
  memset( hw_desc, '\0', DESC_STR_LEN );
  memset( sw_desc, '\0', DESC_STR_LEN );
  memset( serial_num, '\0', SERIAL_NUM_LEN );
  memset( dp_desc, '\0', DESC_STR_LEN );
  sprintf( mfr_desc, "NEC Coporation" );
  sprintf( hw_desc, "OpenFlow Switch Hardware" );
  sprintf( sw_desc, "OpenFlow Switch Software" );
  sprintf( serial_num, "123456" );
  sprintf( dp_desc, "Datapath 0" );

  buffer = create_desc_multipart_reply( TRANSACTION_ID, flags, mfr_desc, hw_desc,
                                    sw_desc, serial_num, dp_desc );

  multipart_reply = buffer->data;
  body_len = ( uint32_t ) ( ntohs( multipart_reply->header.length ) -
                            offsetof( struct ofp_multipart_reply, body ) );

  expect_memory( mock_multipart_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_value( mock_multipart_reply_handler, transaction_id, TRANSACTION_ID );
  expect_value( mock_multipart_reply_handler, type32, OFPMP_DESC );
  expect_value( mock_multipart_reply_handler, flags32, ( uint32_t ) flags );
  expect_value( mock_multipart_reply_handler, data->length, body_len );
  expect_memory( mock_multipart_reply_handler, data->data, multipart_reply->body, body_len );
  expect_memory( mock_multipart_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

  set_multipart_reply_handler( mock_multipart_reply_handler, USER_DATA );
  handle_multipart_reply( DATAPATH_ID, buffer );

  free_buffer( buffer );
}


static void
test_handle_multipart_reply_if_type_is_OFPMP_FLOW() {
  void *expected_data;
  uint16_t flags = OFPMPF_REPLY_MORE;
  list_element *expected_list;
  buffer *buffer;
  uint16_t stats_len = 0;
  uint32_t body_len;
  struct ofp_multipart_reply *multipart_reply;
  struct ofp_flow_stats *expected_stats[ 2 ];
  struct ofp_instruction *inst;

  // with match
  {
    create_oxm_match_testdata();
    create_instruction_testdata();

    stats_len = ( uint16_t ) ( offsetof( struct ofp_flow_stats, match ) + expected_ofp_match_len + expected_ofp_instruction_len );

    expected_stats[ 0 ] = xcalloc( 1, stats_len );
    expected_stats[ 1 ] = xcalloc( 1, stats_len );

    expected_stats[ 0 ]->length = stats_len;
    expected_stats[ 0 ]->table_id = 1;
    expected_stats[ 0 ]->pad = 0;
    expected_stats[ 0 ]->duration_sec = 60;
    expected_stats[ 0 ]->duration_nsec = 10000;
    expected_stats[ 0 ]->priority = 1024;
    expected_stats[ 0 ]->idle_timeout = 60;
    expected_stats[ 0 ]->hard_timeout = 3600;
    expected_stats[ 0 ]->flags = OFPFF_NO_BYT_COUNTS;
    memset( expected_stats[ 0 ]->pad2, 0, sizeof( expected_stats[ 0 ]->pad2 ) );
    expected_stats[ 0 ]->cookie = 0x0102030405060708ULL;
    expected_stats[ 0 ]->packet_count = 1000;
    expected_stats[ 0 ]->byte_count = 100000;
    memcpy( &expected_stats[ 0 ]->match, expected_ofp_match, expected_ofp_match_len );
    inst = ( struct ofp_instruction * ) ( ( char * ) &expected_stats[ 0 ]->match + expected_ofp_match_len );
    memcpy( inst, expected_ofp_instruction, expected_ofp_instruction_len );

    memcpy( expected_stats[ 1 ], expected_stats[ 0 ], stats_len );
    expected_stats[ 1 ]->cookie = 0x0203040506070809ULL;

    create_list( &expected_list );
    append_to_tail( &expected_list, expected_stats[ 0 ] );
    append_to_tail( &expected_list, expected_stats[ 1 ] );

    expected_data = xcalloc( 1, ( size_t ) ( stats_len * 2 ) );
    memcpy( expected_data, expected_stats[ 0 ], stats_len );
    memcpy( ( char * ) expected_data + stats_len, expected_stats[ 1 ], stats_len );

    buffer = create_flow_multipart_reply( TRANSACTION_ID, flags, expected_list );

    multipart_reply = buffer->data;
    body_len = ( uint32_t ) ( ntohs( multipart_reply->header.length ) -
                              offsetof( struct ofp_multipart_reply, body ) );

    expect_memory( mock_multipart_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
    expect_value( mock_multipart_reply_handler, transaction_id, TRANSACTION_ID );
    expect_value( mock_multipart_reply_handler, type32, OFPMP_FLOW );
    expect_value( mock_multipart_reply_handler, flags32, ( uint32_t ) flags );
    expect_value( mock_multipart_reply_handler, data->length, body_len );
    expect_memory( mock_multipart_reply_handler, data->data, expected_data, stats_len );
    expect_memory( mock_multipart_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

    set_multipart_reply_handler( mock_multipart_reply_handler, USER_DATA );
    handle_multipart_reply( DATAPATH_ID, buffer );

    xfree( expected_stats[ 0 ] );
    xfree( expected_stats[ 1 ] );
    delete_list( expected_list );

    delete_oxm_match_testdata();
    delete_instruction_testdata();
    free_buffer( buffer );
    xfree( expected_data );
  }
}


static void
test_handle_multipart_reply_if_type_is_OFPMP_AGGREGATE() {
  uint16_t flags = 0;
  uint32_t body_len;
  uint32_t flow_count = 1000;
  uint64_t packet_count = 1000;
  uint64_t byte_count = 10000;
  buffer *buffer;
  struct ofp_multipart_reply *multipart_reply;
  struct ofp_aggregate_stats_reply aggregate_multipart_reply;

  buffer = create_aggregate_multipart_reply( TRANSACTION_ID, flags, packet_count,
                                             byte_count, flow_count );

  multipart_reply = buffer->data;
  body_len = ( uint32_t ) ( ntohs( multipart_reply->header.length ) -
                            offsetof( struct ofp_multipart_reply, body ) );

  expect_memory( mock_multipart_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_value( mock_multipart_reply_handler, transaction_id, TRANSACTION_ID );
  expect_value( mock_multipart_reply_handler, type32, OFPMP_AGGREGATE );
  expect_value( mock_multipart_reply_handler, flags32, ( uint32_t ) flags );
  expect_value( mock_multipart_reply_handler, data->length, body_len );
  ntoh_aggregate_stats( &aggregate_multipart_reply,
                        ( struct ofp_aggregate_stats_reply * ) multipart_reply->body );
  expect_memory( mock_multipart_reply_handler, data->data, &aggregate_multipart_reply, body_len );
  expect_memory( mock_multipart_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

  set_multipart_reply_handler( mock_multipart_reply_handler, USER_DATA );
  handle_multipart_reply( DATAPATH_ID, buffer );

  free_buffer( buffer );
}


static void
test_handle_multipart_reply_if_type_is_OFPMP_TABLE() {
  void *expected_data;
  uint16_t flags = OFPMPF_REPLY_MORE;
  uint16_t stats_len;
  uint32_t body_len;
  buffer *buffer;
  list_element *table_stats;
  struct ofp_multipart_reply *multipart_reply;
  struct ofp_table_stats *stats[ 2 ];

  stats_len = sizeof( struct ofp_table_stats );

  stats[ 0 ] = xcalloc( 1, stats_len );
  stats[ 1 ] = xcalloc( 1, stats_len );

  stats[ 0 ]->table_id = 1;
  memset( stats[ 0 ]->pad, 0, sizeof( stats[ 0 ]->pad ));
  stats[ 0 ]->active_count = 1000;
  stats[ 0 ]->lookup_count = 100000;
  stats[ 0 ]->matched_count = 10000;

  memcpy( stats[ 1 ], stats[ 0 ], stats_len );
  stats[ 1 ]->table_id = 2;

  create_list( &table_stats );
  append_to_tail( &table_stats, stats[ 0 ] );
  append_to_tail( &table_stats, stats[ 1 ] );

  expected_data = xcalloc( 1, ( size_t ) ( stats_len * 2 ) );
  memcpy( expected_data, stats[ 0 ], stats_len );
  memcpy( ( char * ) expected_data + stats_len, stats[ 1 ], stats_len );

  buffer = create_table_multipart_reply( TRANSACTION_ID, flags, table_stats );

  multipart_reply = buffer->data;
  body_len = ( uint32_t ) ( ntohs( multipart_reply->header.length ) -
                            offsetof( struct ofp_multipart_reply, body ) );

  expect_memory( mock_multipart_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_value( mock_multipart_reply_handler, transaction_id, TRANSACTION_ID );
  expect_value( mock_multipart_reply_handler, type32, OFPMP_TABLE );
  expect_value( mock_multipart_reply_handler, flags32, ( uint32_t ) flags );
  expect_value( mock_multipart_reply_handler, data->length, body_len );
  expect_memory( mock_multipart_reply_handler, data->data, expected_data, stats_len );
  expect_memory( mock_multipart_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

  set_multipart_reply_handler( mock_multipart_reply_handler, USER_DATA );
  handle_multipart_reply( DATAPATH_ID, buffer );

  xfree( stats[ 0 ] );
  xfree( stats[ 1 ] );
  delete_list( table_stats );
  xfree( expected_data );
  free_buffer( buffer );
}


static void
test_handle_multipart_reply_if_type_is_OFPMP_PORT_STATS() {
  void *expected_data;
  uint16_t flags = OFPMPF_REPLY_MORE;
  uint16_t stats_len;
  uint32_t body_len;
  buffer *buffer;
  list_element *port_stats;
  struct ofp_multipart_reply *multipart_reply;
  struct ofp_port_stats *stats[ 2 ];

  stats_len = sizeof( struct ofp_port_stats );

  stats[ 0 ] = xcalloc( 1, stats_len );
  stats[ 1 ] = xcalloc( 1, stats_len );

  stats[ 0 ]->port_no = 1;
  memset( stats[ 0 ]->pad, 0, sizeof( stats[ 0 ]->pad ));
  stats[ 0 ]->rx_packets = 10000;
  stats[ 0 ]->tx_packets = 20000;
  stats[ 0 ]->rx_bytes = 30000;
  stats[ 0 ]->tx_bytes = 40000;
  stats[ 0 ]->rx_dropped = 50000;
  stats[ 0 ]->tx_dropped = 60000;
  stats[ 0 ]->rx_errors = 70000;
  stats[ 0 ]->tx_errors = 80000;
  stats[ 0 ]->rx_frame_err = 1;
  stats[ 0 ]->rx_over_err = 2;
  stats[ 0 ]->rx_crc_err = 1;
  stats[ 0 ]->collisions = 3;
  stats[ 0 ]->duration_sec = 10;
  stats[ 0 ]->duration_nsec = 100;

  memcpy( stats[ 1 ], stats[ 0 ], stats_len );
  stats[ 1 ]->port_no = 2;

  create_list( &port_stats );
  append_to_tail( &port_stats, stats[ 0 ] );
  append_to_tail( &port_stats, stats[ 1 ] );

  expected_data = xcalloc( 1, ( size_t ) ( stats_len * 2 ) );
  memcpy( expected_data, stats[ 0 ], stats_len );
  memcpy( ( char * ) expected_data + stats_len, stats[ 1 ], stats_len );

  buffer = create_port_multipart_reply( TRANSACTION_ID, flags, port_stats );

  multipart_reply = buffer->data;
  body_len = ( uint32_t ) ( ntohs( multipart_reply->header.length ) -
                            offsetof( struct ofp_multipart_reply, body ) );

  expect_memory( mock_multipart_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_value( mock_multipart_reply_handler, transaction_id, TRANSACTION_ID );
  expect_value( mock_multipart_reply_handler, type32, OFPMP_PORT_STATS );
  expect_value( mock_multipart_reply_handler, flags32, ( uint32_t ) flags );
  expect_value( mock_multipart_reply_handler, data->length, body_len );
  expect_memory( mock_multipart_reply_handler, data->data, expected_data, stats_len );
  expect_memory( mock_multipart_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

  set_multipart_reply_handler( mock_multipart_reply_handler, USER_DATA );
  handle_multipart_reply( DATAPATH_ID, buffer );

  xfree( stats[ 0 ] );
  xfree( stats[ 1 ] );
  delete_list( port_stats );
  xfree( expected_data );
  free_buffer( buffer );
}


static void
test_handle_multipart_reply_if_type_is_OFPMP_QUEUE() {
  void *expected_data;
  uint16_t flags = OFPMPF_REPLY_MORE;
  uint16_t stats_len;
  uint32_t body_len;
  buffer *buffer;
  list_element *queue_stats;
  struct ofp_multipart_reply *multipart_reply;
  struct ofp_queue_stats *stats[ 2 ];

  stats_len = sizeof( struct ofp_queue_stats );

  stats[ 0 ] = xcalloc( 1, stats_len );
  stats[ 1 ] = xcalloc( 1, stats_len );

  stats[ 0 ]->port_no = 1;
  stats[ 0 ]->queue_id = 2;
  stats[ 0 ]->tx_bytes = 100000;
  stats[ 0 ]->tx_packets = 60000;
  stats[ 0 ]->tx_errors = 80;
  stats[ 0 ]->duration_sec = 10;
  stats[ 0 ]->duration_nsec = 100;

  memcpy( stats[ 1 ], stats[ 0 ], stats_len );
  stats[ 1 ]->queue_id = 3;

  create_list( &queue_stats );
  append_to_tail( &queue_stats, stats[ 0 ] );
  append_to_tail( &queue_stats, stats[ 1 ] );

  expected_data = xcalloc( 1, ( size_t ) ( stats_len * 2 ) );
  memcpy( expected_data, stats[ 0 ], stats_len );
  memcpy( ( char * ) expected_data + stats_len, stats[ 1 ], stats_len );

  buffer = create_queue_multipart_reply( TRANSACTION_ID, flags, queue_stats );

  multipart_reply = buffer->data;
  body_len = ( uint32_t ) ( ntohs( multipart_reply->header.length ) -
                            offsetof( struct ofp_multipart_reply, body ) );

  expect_memory( mock_multipart_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_value( mock_multipart_reply_handler, transaction_id, TRANSACTION_ID );
  expect_value( mock_multipart_reply_handler, type32, OFPMP_QUEUE );
  expect_value( mock_multipart_reply_handler, flags32, ( uint32_t ) flags );
  expect_value( mock_multipart_reply_handler, data->length, body_len );
  expect_memory( mock_multipart_reply_handler, data->data, expected_data, stats_len );
  expect_memory( mock_multipart_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

  set_multipart_reply_handler( mock_multipart_reply_handler, USER_DATA );
  handle_multipart_reply( DATAPATH_ID, buffer );

  xfree( stats[ 0 ] );
  xfree( stats[ 1 ] );
  delete_list( queue_stats );
  xfree( expected_data );
  free_buffer( buffer );
}


static void
test_handle_multipart_reply_if_type_is_OFPMP_GROUP() {
  void *expected_data;
  uint16_t flags = OFPMPF_REPLY_MORE;
  uint16_t stats_len;
  uint32_t body_len;
  size_t grpsts_0len, grpsts_1len;
  list_element *list;
  buffer *buffer;
  struct ofp_group_stats *grpsts[ 2 ];
  struct ofp_bucket_counter *bktcnt;
  struct ofp_multipart_reply *multipart_reply;

  grpsts_0len = offsetof( struct ofp_group_stats, bucket_stats ) + sizeof( struct ofp_bucket_counter );
  grpsts_1len = offsetof( struct ofp_group_stats, bucket_stats ) + sizeof( struct ofp_bucket_counter );

  stats_len = ( uint16_t ) ( grpsts_0len + grpsts_1len );

  grpsts[ 0 ] = xcalloc( 1, grpsts_0len );
  grpsts[ 1 ] = xcalloc( 1, grpsts_1len );

  grpsts[ 0 ]->length = ( uint16_t ) grpsts_0len;
  grpsts[ 0 ]->group_id = 1;
  grpsts[ 0 ]->ref_count = 2;
  grpsts[ 0 ]->packet_count = 3;
  grpsts[ 0 ]->byte_count = 4;
  grpsts[ 0 ]->duration_sec = 5;
  grpsts[ 0 ]->duration_nsec = 6;
  bktcnt = ( struct ofp_bucket_counter * ) grpsts[ 0 ]->bucket_stats;
  bktcnt->packet_count = 7;
  bktcnt->byte_count = 8;

  grpsts[ 1 ]->length = ( uint16_t ) grpsts_1len;
  grpsts[ 1 ]->group_id = 11;
  grpsts[ 1 ]->ref_count = 12;
  grpsts[ 1 ]->packet_count = 13;
  grpsts[ 1 ]->byte_count = 14;
  grpsts[ 1 ]->duration_sec = 15;
  grpsts[ 1 ]->duration_nsec = 16;
  bktcnt = ( struct ofp_bucket_counter * ) grpsts[ 1 ]->bucket_stats;
  bktcnt->packet_count = 17;
  bktcnt->byte_count = 18;

  create_list( &list );
  append_to_tail( &list, grpsts[ 0 ] );
  append_to_tail( &list, grpsts[ 1 ] );

  expected_data = xcalloc( 1, ( size_t ) ( grpsts_0len + grpsts_1len ) );
  memcpy( expected_data, grpsts[ 0 ], grpsts_0len );
  memcpy( ( char * ) expected_data + grpsts_0len, grpsts[ 1 ], grpsts_1len );

  buffer = create_group_multipart_reply( TRANSACTION_ID, flags, list );

  multipart_reply = buffer->data;
  body_len = ( uint32_t ) ( ntohs( multipart_reply->header.length ) -
                            offsetof( struct ofp_multipart_reply, body ) );

  expect_memory( mock_multipart_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_value( mock_multipart_reply_handler, transaction_id, TRANSACTION_ID );
  expect_value( mock_multipart_reply_handler, type32, OFPMP_GROUP );
  expect_value( mock_multipart_reply_handler, flags32, ( uint32_t ) flags );
  expect_value( mock_multipart_reply_handler, data->length, body_len );
  expect_memory( mock_multipart_reply_handler, data->data, expected_data, stats_len );
  expect_memory( mock_multipart_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

  set_multipart_reply_handler( mock_multipart_reply_handler, USER_DATA );
  handle_multipart_reply( DATAPATH_ID, buffer );

  xfree( grpsts[ 0 ] );
  xfree( grpsts[ 1 ] );
  delete_list( list );
  xfree( expected_data );
  free_buffer( buffer );
}


static void
test_handle_multipart_reply_if_type_is_OFPMP_GROUP_DESC() {
  void *expected_data;
  uint16_t flags = OFPMPF_REPLY_MORE;
  uint16_t stats_len;
  uint32_t body_len;
  uint16_t grpdsc_len[2];
  buffer *buffer;
  list_element *expected_list;
  struct ofp_group_desc *dsc1, *dsc2;
  struct ofp_multipart_reply *multipart_reply;

  create_bucket_testdata();

  grpdsc_len[0] = ( uint16_t ) ( offsetof( struct ofp_group_desc, buckets ) + bucket_testdata_len[0] );
  dsc1 = xcalloc( 1, grpdsc_len[0] );
  dsc1->length = grpdsc_len[0];
  dsc1->type = OFPGT_SELECT;
  dsc1->group_id = 0x11223344;
  memcpy( dsc1->buckets, bucket_testdata[0], bucket_testdata_len[0] );

  grpdsc_len[1] = ( uint16_t ) ( offsetof( struct ofp_group_desc, buckets ) + bucket_testdata_len[1] );
  dsc2 = xcalloc( 1, grpdsc_len[1] );
  dsc2->length = grpdsc_len[1];
  dsc2->type = OFPGT_INDIRECT;
  dsc2->group_id = 0x55667788;
  memcpy( dsc2->buckets, bucket_testdata[1], bucket_testdata_len[1] );

  stats_len = ( uint16_t ) ( grpdsc_len[0] + grpdsc_len[1] );

  create_list( &expected_list );
  append_to_tail( &expected_list, dsc1 );
  append_to_tail( &expected_list, dsc2 );

  expected_data = xcalloc( 1, ( size_t ) ( stats_len ) );
  memcpy( expected_data, dsc1, grpdsc_len[0] );
  memcpy( ( char * ) expected_data + grpdsc_len[0], dsc2, grpdsc_len[1] );

  buffer = create_group_desc_multipart_reply( TRANSACTION_ID, flags, expected_list );

  multipart_reply = buffer->data;
  body_len = ( uint32_t ) ( ntohs( multipart_reply->header.length ) -
                            offsetof( struct ofp_multipart_reply, body ) );

  expect_memory( mock_multipart_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_value( mock_multipart_reply_handler, transaction_id, TRANSACTION_ID );
  expect_value( mock_multipart_reply_handler, type32, OFPMP_GROUP_DESC );
  expect_value( mock_multipart_reply_handler, flags32, ( uint32_t ) flags );
  expect_value( mock_multipart_reply_handler, data->length, body_len );
  expect_memory( mock_multipart_reply_handler, data->data, expected_data, stats_len );
  expect_memory( mock_multipart_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

  set_multipart_reply_handler( mock_multipart_reply_handler, USER_DATA );
  handle_multipart_reply( DATAPATH_ID, buffer );

  delete_bucket_testdata();
  xfree( dsc1 );
  xfree( dsc2 );
  delete_list( expected_list );
  xfree( expected_data );
  free_buffer( buffer );
}


static void
test_handle_multipart_reply_if_type_is_OFPMP_GROUP_FEATURES() {
  void *expected_data;
  uint16_t flags = OFPMPF_REPLY_MORE;
  uint16_t stats_len;
  uint32_t body_len;
  buffer *buffer;
  struct ofp_group_features *grpftr;
  struct ofp_multipart_reply *multipart_reply;

  uint16_t grpftr_len = sizeof( struct ofp_group_features );

  stats_len = grpftr_len;

  grpftr = xcalloc( 1, grpftr_len );
  grpftr->types = OFPGT_SELECT;
  grpftr->capabilities = OFPGFC_CHAINING;
  grpftr->max_groups[0] = 1;
  grpftr->max_groups[1] = 2;
  grpftr->max_groups[2] = 3;
  grpftr->max_groups[3] = 4;
  grpftr->actions[0] = 5;
  grpftr->actions[1] = 6;
  grpftr->actions[2] = 7;
  grpftr->actions[3] = 8;

  buffer = create_group_features_multipart_reply( TRANSACTION_ID, flags, grpftr->types,
    grpftr->capabilities, grpftr->max_groups, grpftr->actions );

  expected_data = grpftr;

  multipart_reply = buffer->data;
  body_len = ( uint32_t ) ( ntohs( multipart_reply->header.length ) -
                            offsetof( struct ofp_multipart_reply, body ) );

  expect_memory( mock_multipart_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_value( mock_multipart_reply_handler, transaction_id, TRANSACTION_ID );
  expect_value( mock_multipart_reply_handler, type32, OFPMP_GROUP_FEATURES );
  expect_value( mock_multipart_reply_handler, flags32, ( uint32_t ) flags );
  expect_value( mock_multipart_reply_handler, data->length, body_len );
  expect_memory( mock_multipart_reply_handler, data->data, expected_data, stats_len );
  expect_memory( mock_multipart_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

  set_multipart_reply_handler( mock_multipart_reply_handler, USER_DATA );
  handle_multipart_reply( DATAPATH_ID, buffer );

  xfree( expected_data );
  free_buffer( buffer );
}


static void
test_handle_multipart_reply_if_type_is_OFPMP_METER() {
  void *expected_data;
  uint16_t flags = OFPMPF_REPLY_MORE;
  uint16_t stats_len;
  uint32_t body_len;
  uint16_t mtrsts_len[2];
  buffer *buffer;
  list_element *expected_list;
  struct ofp_meter_stats *mtr1, *mtr2;
  struct ofp_meter_band_stats *mtrbnd;
  struct ofp_multipart_reply *multipart_reply;

  mtrsts_len[0] = ( uint16_t ) ( offsetof( struct ofp_meter_stats, band_stats ) + sizeof( struct ofp_meter_band_stats ) );
  mtr1 = xcalloc( 1, mtrsts_len[0] );
  mtr1->meter_id = 0xaabbccdd;
  mtr1->len = mtrsts_len[0];
  mtr1->flow_count = 1;
  mtr1->packet_in_count = 2;
  mtr1->byte_in_count = 3;
  mtr1->duration_sec = 4;
  mtr1->duration_nsec = 5;
  mtrbnd = mtr1->band_stats;
  mtrbnd->packet_band_count = 0x11223344;
  mtrbnd->byte_band_count = 0x55667788;

  mtrsts_len[1] = ( uint16_t ) ( offsetof( struct ofp_meter_stats, band_stats ) + sizeof( struct ofp_meter_band_stats ) );
  mtr2 = xcalloc( 1, mtrsts_len[1] );
  mtr2->meter_id = 0x12345566;
  mtr2->len = mtrsts_len[1];
  mtr2->flow_count = 1;
  mtr2->packet_in_count = 2;
  mtr2->byte_in_count = 3;
  mtr2->duration_sec = 4;
  mtr2->duration_nsec = 5;
  mtrbnd = mtr2->band_stats;
  mtrbnd->packet_band_count = 0x11223344;
  mtrbnd->byte_band_count = 0x55667788;

  stats_len = ( uint16_t ) ( mtrsts_len[0] + mtrsts_len[1] );

  create_list( &expected_list );
  append_to_tail( &expected_list, mtr1 );
  append_to_tail( &expected_list, mtr2 );

  expected_data = xcalloc( 1, ( size_t ) ( stats_len ) );
  memcpy( expected_data, mtr1, mtrsts_len[0] );
  memcpy( ( char * ) expected_data + mtrsts_len[0], mtr2, mtrsts_len[1] );

  buffer = create_meter_multipart_reply( TRANSACTION_ID, flags, expected_list );

  multipart_reply = buffer->data;
  body_len = ( uint32_t ) ( ntohs( multipart_reply->header.length ) -
                            offsetof( struct ofp_multipart_reply, body ) );

  expect_memory( mock_multipart_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_value( mock_multipart_reply_handler, transaction_id, TRANSACTION_ID );
  expect_value( mock_multipart_reply_handler, type32, OFPMP_METER );
  expect_value( mock_multipart_reply_handler, flags32, ( uint32_t ) flags );
  expect_value( mock_multipart_reply_handler, data->length, body_len );
  expect_memory( mock_multipart_reply_handler, data->data, expected_data, stats_len );
  expect_memory( mock_multipart_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

  set_multipart_reply_handler( mock_multipart_reply_handler, USER_DATA );
  handle_multipart_reply( DATAPATH_ID, buffer );

  xfree( mtr1 );
  xfree( mtr2 );
  delete_list( expected_list );
  xfree( expected_data );
  free_buffer( buffer );
}


static void
test_handle_multipart_reply_if_type_is_OFPMP_METER_CONFIG() {
  void *expected_data;
  uint16_t flags = OFPMPF_REPLY_MORE;
  uint16_t stats_len;
  uint32_t body_len;
  uint16_t mtrcfg_len[2];
  buffer *buffer;
  list_element *expected_list;
  struct ofp_meter_config *mtr1, *mtr2;
  struct ofp_meter_band_drop *mtrbnd;
  struct ofp_multipart_reply *multipart_reply;

  mtrcfg_len[0] = ( uint16_t ) ( offsetof( struct ofp_meter_config, bands ) + sizeof( struct ofp_meter_band_drop ) );
  mtr1 = xcalloc( 1, mtrcfg_len[0] );
  mtr1->length = mtrcfg_len[0];
  mtr1->flags = OFPMC_MODIFY;
  mtr1->meter_id = 1;
  mtrbnd = ( struct ofp_meter_band_drop * ) mtr1->bands;
  mtrbnd->type = OFPMBT_DROP;
  mtrbnd->len = sizeof( struct ofp_meter_band_drop );
  mtrbnd->rate = 0x11223344;
  mtrbnd->burst_size = 0x55667788;

  mtrcfg_len[1] = ( uint16_t ) ( offsetof( struct ofp_meter_config, bands ) + sizeof( struct ofp_meter_band_drop ) );
  mtr2 = xcalloc( 1, mtrcfg_len[1] );
  mtr2->length = mtrcfg_len[1];
  mtr2->flags = OFPMC_DELETE;
  mtr2->meter_id = 1;
  mtrbnd = ( struct ofp_meter_band_drop * ) mtr2->bands;
  mtrbnd->type = OFPMBT_DROP;
  mtrbnd->len = sizeof( struct ofp_meter_band_drop );
  mtrbnd->rate = 0x12345555;
  mtrbnd->burst_size = 0x56789999;

  stats_len = ( uint16_t ) ( mtrcfg_len[0] + mtrcfg_len[1] );

  create_list( &expected_list );
  append_to_tail( &expected_list, mtr1 );
  append_to_tail( &expected_list, mtr2 );

  expected_data = xcalloc( 1, ( size_t ) ( stats_len ) );
  memcpy( expected_data, mtr1, mtrcfg_len[0] );
  memcpy( ( char * ) expected_data + mtrcfg_len[0], mtr2, mtrcfg_len[1] );

  buffer = create_meter_config_multipart_reply( TRANSACTION_ID, flags, expected_list );

  multipart_reply = buffer->data;
  body_len = ( uint32_t ) ( ntohs( multipart_reply->header.length ) -
                            offsetof( struct ofp_multipart_reply, body ) );

  expect_memory( mock_multipart_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_value( mock_multipart_reply_handler, transaction_id, TRANSACTION_ID );
  expect_value( mock_multipart_reply_handler, type32, OFPMP_METER_CONFIG );
  expect_value( mock_multipart_reply_handler, flags32, ( uint32_t ) flags );
  expect_value( mock_multipart_reply_handler, data->length, body_len );
  expect_memory( mock_multipart_reply_handler, data->data, expected_data, stats_len );
  expect_memory( mock_multipart_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

  set_multipart_reply_handler( mock_multipart_reply_handler, USER_DATA );
  handle_multipart_reply( DATAPATH_ID, buffer );

  xfree( mtr1 );
  xfree( mtr2 );
  delete_list( expected_list );
  xfree( expected_data );
  free_buffer( buffer );
}


static void
test_handle_multipart_reply_if_type_is_OFPMP_METER_FEATURES() {
  void *expected_data;
  uint16_t flags = OFPMPF_REPLY_MORE;
  uint16_t stats_len;
  uint32_t body_len;
  buffer *buffer;
  struct ofp_multipart_reply *multipart_reply;
  struct ofp_meter_features *mtrftr;

  stats_len = sizeof( struct ofp_meter_features );
  mtrftr = xcalloc( 1, stats_len );
  mtrftr->max_meter = 1;
  mtrftr->band_types = OFPMBT_DROP;
  mtrftr->capabilities = OFPMF_KBPS;
  mtrftr->max_bands = 10;
  mtrftr->max_color = 20;
  memset( mtrftr->pad, 0, sizeof( mtrftr->pad ) );

  buffer = create_meter_features_multipart_reply( TRANSACTION_ID, flags, mtrftr->max_meter,
    mtrftr->band_types, mtrftr->capabilities, mtrftr->max_bands, mtrftr->max_color );

  expected_data = mtrftr;

  multipart_reply = buffer->data;
  body_len = ( uint32_t ) ( ntohs( multipart_reply->header.length ) -
                            offsetof( struct ofp_multipart_reply, body ) );

  expect_memory( mock_multipart_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_value( mock_multipart_reply_handler, transaction_id, TRANSACTION_ID );
  expect_value( mock_multipart_reply_handler, type32, OFPMP_METER_FEATURES );
  expect_value( mock_multipart_reply_handler, flags32, ( uint32_t ) flags );
  expect_value( mock_multipart_reply_handler, data->length, body_len );
  expect_memory( mock_multipart_reply_handler, data->data, expected_data, stats_len );
  expect_memory( mock_multipart_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

  set_multipart_reply_handler( mock_multipart_reply_handler, USER_DATA );
  handle_multipart_reply( DATAPATH_ID, buffer );

  xfree( expected_data );
  free_buffer( buffer );
}


static void
test_handle_multipart_reply_if_type_is_OFPMP_TABLE_FEATURES() {
  void *expected_data;
  uint16_t flags = OFPMPF_REPLY_MORE;
  uint16_t stats_len;
  uint32_t body_len;
  buffer *buffer;
  list_element *table_ftr_stats;
  struct ofp_multipart_reply *multipart_reply;
  struct ofp_table_features *stats[ 2 ];
  char name[OFP_MAX_TABLE_NAME_LEN] = "TableName";

  stats_len = sizeof( struct ofp_table_features );

  stats[ 0 ] = xcalloc( 1, stats_len );
  stats[ 1 ] = xcalloc( 1, stats_len );

  stats[ 0 ]->length = ( uint16_t ) sizeof( struct ofp_table_features );
  stats[ 0 ]->table_id = 1;
  memset( stats[ 0 ]->pad, 0, sizeof( stats[ 0 ]->pad ) );
  memcpy( stats[ 0 ]->name, name, sizeof( name ) );
  stats[ 0 ]->metadata_match = 0x1111222233334444;
  stats[ 0 ]->metadata_write = 0x5555666677778888;
  stats[ 0 ]->config = 0x12345678;
  stats[ 0 ]->max_entries = 0xAABBCCDD;

  memcpy( stats[ 1 ], stats[ 0 ], stats_len );
  stats[ 1 ]->table_id = 2;

  create_list( &table_ftr_stats );
  append_to_tail( &table_ftr_stats, stats[ 0 ] );
  append_to_tail( &table_ftr_stats, stats[ 1 ] );

  expected_data = xcalloc( 1, ( size_t ) ( stats_len * 2 ) );
  memcpy( expected_data, stats[ 0 ], stats_len );
  memcpy( ( char * ) expected_data + stats_len, stats[ 1 ], stats_len );

  buffer = create_table_features_multipart_reply( TRANSACTION_ID, flags, table_ftr_stats );

  multipart_reply = buffer->data;
  body_len = ( uint32_t ) ( ntohs( multipart_reply->header.length ) -
                            offsetof( struct ofp_multipart_reply, body ) );

  expect_memory( mock_multipart_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_value( mock_multipart_reply_handler, transaction_id, TRANSACTION_ID );
  expect_value( mock_multipart_reply_handler, type32, OFPMP_TABLE_FEATURES );
  expect_value( mock_multipart_reply_handler, flags32, ( uint32_t ) flags );
  expect_value( mock_multipart_reply_handler, data->length, body_len );
  expect_memory( mock_multipart_reply_handler, data->data, expected_data, stats_len );
  expect_memory( mock_multipart_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

  set_multipart_reply_handler( mock_multipart_reply_handler, USER_DATA );
  handle_multipart_reply( DATAPATH_ID, buffer );

  xfree( stats[ 0 ] );
  xfree( stats[ 1 ] );
  delete_list( table_ftr_stats );
  xfree( expected_data );
  free_buffer( buffer );
}


static void
test_handle_multipart_reply_if_type_is_OFPMP_PORT_DESC() {
  void *expected_data;
  uint16_t flags = OFPMPF_REPLY_MORE;
  uint16_t stats_len;
  uint32_t body_len;
  buffer *buffer;
  list_element *port_desc_stats;
  struct ofp_multipart_reply *multipart_reply;
  struct ofp_port *stats[ 2 ];
  char name[OFP_MAX_PORT_NAME_LEN] = "PortName";

  stats_len = sizeof( struct ofp_port );

  stats[ 0 ] = xcalloc( 1, stats_len );
  stats[ 1 ] = xcalloc( 1, stats_len );

  stats[ 0 ]->port_no = 1;
  memset( stats[ 0 ]->pad, 0, sizeof( stats[ 0 ]->pad ) );
  memcpy( stats[ 0 ]->hw_addr, MAC_ADDR_X, sizeof( OFP_ETH_ALEN ) );
  memset( stats[ 0 ]->pad2, 0, sizeof( stats[ 0 ]->pad2 ) );
  memcpy( stats[ 0 ]->name, name, sizeof( name ) );
  stats[ 0 ]->config = OFPPC_PORT_DOWN;
  stats[ 0 ]->state = OFPPS_BLOCKED;
  stats[ 0 ]->curr = 0x12345678;
  stats[ 0 ]->advertised = 0x9ABCDEF0;
  stats[ 0 ]->supported = 0xFEDCBA90;
  stats[ 0 ]->peer = 0x87654321;
  stats[ 0 ]->curr_speed = 0x11223344;
  stats[ 0 ]->max_speed = 0xAABBCCDD;

  memcpy( stats[ 1 ], stats[ 0 ], stats_len );
  stats[ 1 ]->port_no = 2;

  create_list( &port_desc_stats );
  append_to_tail( &port_desc_stats, stats[ 0 ] );
  append_to_tail( &port_desc_stats, stats[ 1 ] );

  expected_data = xcalloc( 1, ( size_t ) ( stats_len * 2 ) );
  memcpy( expected_data, stats[ 0 ], stats_len );
  memcpy( ( char * ) expected_data + stats_len, stats[ 1 ], stats_len );

  buffer = create_port_desc_multipart_reply( TRANSACTION_ID, flags, port_desc_stats );

  multipart_reply = buffer->data;
  body_len = ( uint32_t ) ( ntohs( multipart_reply->header.length ) -
                            offsetof( struct ofp_multipart_reply, body ) );

  expect_memory( mock_multipart_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_value( mock_multipart_reply_handler, transaction_id, TRANSACTION_ID );
  expect_value( mock_multipart_reply_handler, type32, OFPMP_PORT_DESC );
  expect_value( mock_multipart_reply_handler, flags32, ( uint32_t ) flags );
  expect_value( mock_multipart_reply_handler, data->length, body_len );
  expect_memory( mock_multipart_reply_handler, data->data, expected_data, stats_len );
  expect_memory( mock_multipart_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

  set_multipart_reply_handler( mock_multipart_reply_handler, USER_DATA );
  handle_multipart_reply( DATAPATH_ID, buffer );

  xfree( stats[ 0 ] );
  xfree( stats[ 1 ] );
  delete_list( port_desc_stats );
  xfree( expected_data );
  free_buffer( buffer );
}


static void
test_handle_multipart_reply_if_type_is_OFPMP_EXPERIMENTER() {
  void *expected_data;
  uint16_t flags = 0;
  uint16_t stats_len;
  uint32_t body_len;
  uint32_t experimenter = VENDOR_ID;
  uint32_t exp_type = 1;
  buffer *body, *experimenter_multipart_reply;
  struct ofp_multipart_reply *multipart_reply;
  struct ofp_experimenter_multipart_header *stats;

  body = alloc_buffer_with_length( 128 );
  append_back_buffer( body, 128 );
  memset( body->data, 0xa1, body->length );
  experimenter_multipart_reply = create_experimenter_multipart_reply( TRANSACTION_ID, flags, experimenter, exp_type, body );

  stats_len = ( uint16_t ) ( sizeof( struct ofp_experimenter_multipart_header ) + body->length );

  expected_data = xcalloc( 1, ( size_t ) stats_len );
  stats = ( struct ofp_experimenter_multipart_header * ) expected_data;
  stats->experimenter = experimenter;
  stats->exp_type = exp_type;
  memcpy( stats + 1, body->data, body->length );

  multipart_reply = experimenter_multipart_reply->data;
  body_len = ( uint32_t ) ( ntohs( multipart_reply->header.length ) -
                            offsetof( struct ofp_multipart_reply, body ) );

  expect_memory( mock_multipart_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_value( mock_multipart_reply_handler, transaction_id, TRANSACTION_ID );
  expect_value( mock_multipart_reply_handler, type32, OFPMP_EXPERIMENTER );
  expect_value( mock_multipart_reply_handler, flags32, ( uint32_t ) flags );
  expect_value( mock_multipart_reply_handler, data->length, body_len );
  expect_memory( mock_multipart_reply_handler, data->data, expected_data, body_len );
  expect_memory( mock_multipart_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

  set_multipart_reply_handler( mock_multipart_reply_handler, USER_DATA );
  handle_multipart_reply( DATAPATH_ID, experimenter_multipart_reply );

  xfree( expected_data );
  free_buffer( body );
  free_buffer( experimenter_multipart_reply );
}


static void
test_handle_multipart_reply_with_undefined_type() {
  void *expected_data;
  uint16_t flags = 0;
  uint16_t stats_len;
  uint32_t experimenter = VENDOR_ID;
  uint32_t exp_type = 1;
  buffer *body, *experimenter_multipart_reply;
  struct ofp_multipart_reply *multipart_reply;
  struct ofp_experimenter_multipart_header *stats;

  body = alloc_buffer_with_length( 128 );
  append_back_buffer( body, 128 );
  memset( body->data, 0xa1, body->length );
  experimenter_multipart_reply = create_experimenter_multipart_reply( TRANSACTION_ID, flags, experimenter, exp_type, body );

  stats_len = ( uint16_t ) ( sizeof( struct ofp_experimenter_multipart_header ) + body->length );

  expected_data = xcalloc( 1, ( size_t ) stats_len );
  stats = ( struct ofp_experimenter_multipart_header * ) expected_data;
  stats->experimenter = experimenter;
  stats->exp_type = exp_type;
  memcpy( stats + 1, body->data, body->length );

  multipart_reply = experimenter_multipart_reply->data;
  multipart_reply->type = htons( 0xfffe );

  set_multipart_reply_handler( mock_multipart_reply_handler, USER_DATA );
  expect_assert_failure( handle_multipart_reply( DATAPATH_ID, experimenter_multipart_reply ) );

  xfree( expected_data );
  free_buffer( body );
  free_buffer( experimenter_multipart_reply );
}


static void
test_handle_multipart_reply_if_handler_is_not_registered() {
  char mfr_desc[ DESC_STR_LEN ];
  char hw_desc[ DESC_STR_LEN ];
  char sw_desc[ DESC_STR_LEN ];
  char serial_num[ SERIAL_NUM_LEN ];
  char dp_desc[ DESC_STR_LEN ];
  uint16_t flags = 0;
  buffer *buffer;

  memset( mfr_desc, '\0', DESC_STR_LEN );
  memset( hw_desc, '\0', DESC_STR_LEN );
  memset( sw_desc, '\0', DESC_STR_LEN );
  memset( serial_num, '\0', SERIAL_NUM_LEN );
  memset( dp_desc, '\0', DESC_STR_LEN );
  sprintf( mfr_desc, "NEC Coporation" );
  sprintf( hw_desc, "OpenFlow Switch Hardware" );
  sprintf( sw_desc, "OpenFlow Switch Software" );
  sprintf( serial_num, "123456" );
  sprintf( dp_desc, "Datapath 0" );

  buffer = create_desc_multipart_reply( TRANSACTION_ID, flags, mfr_desc, hw_desc,
                                    sw_desc, serial_num, dp_desc );

  // FIXME
  handle_multipart_reply( DATAPATH_ID, buffer );

  free_buffer( buffer );
}


static void
test_handle_multipart_reply_if_message_is_NULL() {
  set_multipart_reply_handler( mock_multipart_reply_handler, USER_DATA );
  expect_assert_failure( handle_multipart_reply( DATAPATH_ID, NULL ) );
}


static void
test_handle_multipart_reply_if_message_length_is_zero() {
  buffer *buffer;

  buffer = alloc_buffer_with_length( 32 );

  set_multipart_reply_handler( mock_multipart_reply_handler, USER_DATA );
  expect_assert_failure( handle_multipart_reply( DATAPATH_ID, buffer ) );

  free_buffer( buffer );
}


/********************************************************************************
 * handle_barrier_reply() tests.
 ********************************************************************************/

static void
test_handle_barrier_reply() {
  buffer *buffer;

  buffer = create_barrier_reply( TRANSACTION_ID );

  expect_memory( mock_barrier_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_value( mock_barrier_reply_handler, transaction_id, TRANSACTION_ID );
  expect_memory( mock_barrier_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

  set_barrier_reply_handler( mock_barrier_reply_handler, USER_DATA );
  handle_barrier_reply( DATAPATH_ID, buffer );

  free_buffer( buffer );
}


static void
test_handle_barrier_reply_if_handler_is_not_registered() {
  buffer *buffer;

  buffer = create_barrier_reply( TRANSACTION_ID );

  // FIXME
  
  handle_barrier_reply( DATAPATH_ID, buffer );

  free_buffer( buffer );
}


static void
test_handle_barrier_reply_if_message_is_NULL() {
  set_barrier_reply_handler( mock_barrier_reply_handler, USER_DATA );
  expect_assert_failure( handle_barrier_reply( DATAPATH_ID, NULL ) );
}


static void
test_handle_barrier_reply_if_message_length_is_zero() {
  buffer *buffer;

  buffer = alloc_buffer_with_length( 32 );

  set_barrier_reply_handler( mock_barrier_reply_handler, USER_DATA );
  expect_assert_failure( handle_barrier_reply( DATAPATH_ID, buffer ) );

  free_buffer( buffer );
}


/********************************************************************************
 * handle_queue_get_config_reply() tests.
 ********************************************************************************/

static void
test_handle_queue_get_config_reply() {
  size_t queue_len;
  uint32_t port = 1;
  list_element *list;
  buffer *expected_message;
  struct ofp_packet_queue *queue[ 2 ];
  struct ofp_queue_prop_min_rate *prop_header;

  queue_len = offsetof( struct ofp_packet_queue, properties ) + sizeof( struct ofp_queue_prop_min_rate );
  queue[ 0 ] = xcalloc( 1, queue_len );
  queue[ 1 ] = xcalloc( 1, queue_len );

  queue[ 0 ]->queue_id = 1;
  queue[ 0 ]->port = 2;
  queue[ 0 ]->len = ( uint16_t ) queue_len;
  prop_header = ( struct ofp_queue_prop_min_rate * ) queue[ 0 ]->properties;
  prop_header->prop_header.property = OFPQT_MIN_RATE;
  prop_header->prop_header.len = sizeof( struct ofp_queue_prop_min_rate );
  prop_header->rate = 1234;

  queue[ 1 ]->queue_id = 2;
  queue[ 1 ]->port = 3;
  queue[ 1 ]->len = ( uint16_t ) queue_len;
  prop_header = ( struct ofp_queue_prop_min_rate * ) queue[ 1 ]->properties;
  prop_header->prop_header.property = OFPQT_MIN_RATE;
  prop_header->prop_header.len = sizeof( struct ofp_queue_prop_min_rate );
  prop_header->rate = 5678;

  create_list( &list );
  append_to_tail( &list, queue[ 0 ] );
  append_to_tail( &list, queue[ 1 ] );

  expected_message = create_queue_get_config_reply( TRANSACTION_ID, port, list );

  expect_memory( mock_queue_get_config_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_value( mock_queue_get_config_reply_handler, transaction_id, TRANSACTION_ID );
  expect_value( mock_queue_get_config_reply_handler, port, port );
  expect_memory( mock_queue_get_config_reply_handler, queue1, queue[ 0 ], queue_len );
  expect_memory( mock_queue_get_config_reply_handler, queue2, queue[ 1 ], queue_len );
  expect_memory( mock_queue_get_config_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

  set_queue_get_config_reply_handler( mock_queue_get_config_reply_handler, USER_DATA );
  handle_queue_get_config_reply( DATAPATH_ID, expected_message );

  xfree( queue[ 0 ] );
  xfree( queue[ 1 ] );
  delete_list( list );
  free_buffer( expected_message );
}


static void
test_handle_queue_get_config_reply_without_queues() {
  uint16_t port = 1;
  buffer *buffer;

  buffer = create_queue_get_config_reply( TRANSACTION_ID, port, NULL );

  set_queue_get_config_reply_handler( mock_queue_get_config_reply_handler, USER_DATA );
  expect_assert_failure( handle_queue_get_config_reply( DATAPATH_ID, buffer ) );

  free_buffer( buffer );
}


static void
test_handle_queue_get_config_reply_if_handler_is_not_registered() {
  size_t queue_len;
  uint32_t port = 1;
  list_element *list;
  buffer *expected_message;
  struct ofp_packet_queue *queue[ 2 ];
  struct ofp_queue_prop_min_rate *prop_header;

  queue_len = offsetof( struct ofp_packet_queue, properties ) + sizeof( struct ofp_queue_prop_min_rate );
  queue[ 0 ] = xcalloc( 1, queue_len );
  queue[ 1 ] = xcalloc( 1, queue_len );

  queue[ 0 ]->queue_id = 1;
  queue[ 0 ]->port = 2;
  queue[ 0 ]->len = ( uint16_t ) queue_len;
  prop_header = ( struct ofp_queue_prop_min_rate * ) queue[ 0 ]->properties;
  prop_header->prop_header.property = OFPQT_MIN_RATE;
  prop_header->prop_header.len = sizeof( struct ofp_queue_prop_min_rate );
  prop_header->rate = 1234;

  queue[ 1 ]->queue_id = 2;
  queue[ 1 ]->port = 3;
  queue[ 1 ]->len = ( uint16_t ) queue_len;
  prop_header = ( struct ofp_queue_prop_min_rate * ) queue[ 1 ]->properties;
  prop_header->prop_header.property = OFPQT_MIN_RATE;
  prop_header->prop_header.len = sizeof( struct ofp_queue_prop_min_rate );
  prop_header->rate = 5678;

  create_list( &list );
  append_to_tail( &list, queue[ 0 ] );
  append_to_tail( &list, queue[ 1 ] );

  expected_message = create_queue_get_config_reply( TRANSACTION_ID, port, list );

  // FIXME
  handle_queue_get_config_reply( DATAPATH_ID, expected_message );

  xfree( queue[ 0 ] );
  xfree( queue[ 1 ] );
  delete_list( list );
  free_buffer( expected_message );
}


static void
test_handle_queue_get_config_reply_if_message_is_NULL() {
  set_queue_get_config_reply_handler( mock_queue_get_config_reply_handler, USER_DATA );
  expect_assert_failure( handle_queue_get_config_reply( DATAPATH_ID, NULL ) );
}


static void
test_handle_queue_get_config_reply_if_message_length_is_zero() {
  buffer *buffer;

  buffer = alloc_buffer_with_length( 32 );

  set_queue_get_config_reply_handler( mock_queue_get_config_reply_handler, USER_DATA );
  expect_assert_failure( handle_queue_get_config_reply( DATAPATH_ID, buffer ) );

  free_buffer( buffer );
}



/********************************************************************************
 * handle_role_reply() tests.
 ********************************************************************************/

static void
test_handle_role_reply() {
  uint32_t role = OFPCR_ROLE_NOCHANGE;
  uint64_t generation_id = 0xAAAABBBBCCCCDDDD;
  buffer *buffer;

  buffer = create_role_reply( TRANSACTION_ID, role, generation_id );

  expect_memory( mock_role_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_value( mock_role_reply_handler, transaction_id, TRANSACTION_ID );
  expect_value( mock_role_reply_handler, role, role );
  expect_memory( mock_role_reply_handler, &generation_id, &generation_id, sizeof( uint64_t ) );
  expect_memory( mock_role_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

  set_role_reply_handler( mock_role_reply_handler, USER_DATA );
  handle_role_reply( DATAPATH_ID, buffer );

  free_buffer( buffer );
}


static void
test_handle_role_reply_if_handler_is_not_registered() {
  uint32_t role = OFPCR_ROLE_NOCHANGE;
  uint64_t generation_id = 0xAAAABBBBCCCCDDDD;
  buffer *buffer;

  buffer = create_role_reply( TRANSACTION_ID, role, generation_id );

  // FIXME

  handle_role_reply( DATAPATH_ID, buffer );

  free_buffer( buffer );
}


static void
test_handle_role_reply_if_message_is_NULL() {
  set_role_reply_handler( mock_role_reply_handler, USER_DATA );
  expect_assert_failure( handle_role_reply( DATAPATH_ID, NULL ) );
}


static void
test_handle_role_reply_if_message_length_is_zero() {
  buffer *buffer;

  buffer = alloc_buffer_with_length( 32 );

  set_role_reply_handler( mock_role_reply_handler, USER_DATA );
  expect_assert_failure( handle_role_reply( DATAPATH_ID, buffer ) );

  free_buffer( buffer );
}



/********************************************************************************
 * handle_get_async_reply() tests.
 ********************************************************************************/

static void
test_handle_get_async_reply() {
  const uint32_t packet_in_mask[ 2 ] = { 0x01020304, 0x05060708 };
  const uint32_t port_status_mask[ 2 ] = { 0x090A0B0C, 0x0D0E0F01 };
  const uint32_t flow_removed_mask[ 2 ] = { 0x11223344, 0xAABBCCDD };

  buffer *buffer = create_get_async_reply( TRANSACTION_ID, packet_in_mask, port_status_mask, flow_removed_mask );

  expect_memory( mock_get_async_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_value( mock_get_async_reply_handler, transaction_id, TRANSACTION_ID );
  expect_memory( mock_get_async_reply_handler, packet_in_mask, packet_in_mask, (sizeof( uint32_t ) * 2) );
  expect_memory( mock_get_async_reply_handler, port_status_mask, port_status_mask, (sizeof( uint32_t ) * 2) );
  expect_memory( mock_get_async_reply_handler, flow_removed_mask, flow_removed_mask, (sizeof( uint32_t ) * 2) );
  expect_memory( mock_get_async_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

  set_get_async_reply_handler( mock_get_async_reply_handler, USER_DATA );
  handle_get_async_reply( DATAPATH_ID, buffer );

  free_buffer( buffer );
}


static void
test_handle_get_async_reply_if_handler_is_not_registered() {
  const uint32_t packet_in_mask[ 2 ] = { 0x01020304, 0x05060708 };
  const uint32_t port_status_mask[ 2 ] = { 0x090A0B0C, 0x0D0E0F01 };
  const uint32_t flow_removed_mask[ 2 ] = { 0x11223344, 0xAABBCCDD };

  buffer *buffer = create_get_async_reply( TRANSACTION_ID, packet_in_mask, port_status_mask, flow_removed_mask );
  
  // FIXME
  
  handle_get_async_reply( DATAPATH_ID, buffer );

  free_buffer( buffer );
}


static void
test_handle_get_async_reply_if_message_is_NULL() {
  set_get_async_reply_handler( mock_get_async_reply_handler, USER_DATA );
  expect_assert_failure( handle_get_async_reply( DATAPATH_ID, NULL ) );
}


static void
test_handle_get_async_reply_if_message_length_is_zero() {
  buffer *buffer;

  buffer = alloc_buffer_with_length( 32 );

  set_get_async_reply_handler( mock_get_async_reply_handler, USER_DATA );
  expect_assert_failure( handle_get_async_reply( DATAPATH_ID, buffer ) );

  free_buffer( buffer );
}

/********************************************************************************
 * handle_list_switches_reply() tests.
 ********************************************************************************/

static void
test_insert_dpid() {
  list_element *head;
  create_list( &head );
  uint64_t alice = 0x1;
  uint64_t bob = 0x2;
  uint64_t carol = 0x3;

  insert_dpid( &head, &carol );
  insert_dpid( &head, &alice );
  insert_dpid( &head, &bob );

  list_element *element = head;
  assert_true( element != NULL );
  assert_true( element->data != NULL );
  assert_true( alice == *( uint64_t * ) element->data );

  element = element->next;
  assert_true( element != NULL );
  assert_true( element->data != NULL );
  assert_true( bob == *( uint64_t * ) element->data );

  element = element->next;
  assert_true( element != NULL );
  assert_true( element->data != NULL );
  assert_true( carol == *( uint64_t * ) element->data );

  element = element->next;
  assert_true( element == NULL );

  delete_list( head );
}


static void
test_insert_dpid_if_head_is_NULL() {
  uint64_t dpid = 0x1;

  expect_assert_failure( insert_dpid( NULL, &dpid ) );
}


static void
test_insert_dpid_if_dpid_is_NULL() {
  list_element *head;
  create_list( &head );

  expect_assert_failure( insert_dpid( &head, NULL ) );

  delete_list( head );
}


static void
test_handle_list_switches_reply() {
  uint16_t message_type = 0;
  uint64_t alice = 0x1;
  uint64_t bob = 0x2;
  uint64_t carol = 0x3;
  uint64_t dpid[] = { htonll( bob ), htonll( carol ), htonll( alice ) };
  size_t length = sizeof( dpid );
  void *user_data = LIST_SWITCHES_REPLY_USER_DATA;

  expect_value( mock_handle_list_switches_reply, *dpid1, alice );
  expect_value( mock_handle_list_switches_reply, *dpid2, bob );
  expect_value( mock_handle_list_switches_reply, *dpid3, carol );
  expect_value( mock_handle_list_switches_reply, user_data, LIST_SWITCHES_REPLY_USER_DATA );

  set_list_switches_reply_handler( mock_handle_list_switches_reply );
  handle_list_switches_reply( message_type, dpid, length, user_data );
}


static void
test_handle_list_switches_reply_if_data_is_NULL() {
  uint16_t message_type = 0;
  size_t length = 64;
  void *user_data = LIST_SWITCHES_REPLY_USER_DATA;

  set_list_switches_reply_handler( mock_handle_list_switches_reply );
  expect_assert_failure( handle_list_switches_reply( message_type, NULL, length, user_data ) );
}


static void
test_handle_list_switches_reply_if_length_is_zero() {
  uint16_t message_type = 0;
  uint64_t dpid[] = { 0 };
  void *user_data = LIST_SWITCHES_REPLY_USER_DATA;

  expect_value( mock_handle_list_switches_reply, user_data, LIST_SWITCHES_REPLY_USER_DATA );

  set_list_switches_reply_handler( mock_handle_list_switches_reply );
  handle_list_switches_reply( message_type, dpid, 0, user_data );
}


/********************************************************************************
 * handle_switch_events() tests.
 ********************************************************************************/

static void
test_handle_switch_events_if_type_is_MESSENGER_OPENFLOW_CONNECTED() {
  buffer *data = alloc_buffer_with_length( sizeof( openflow_service_header_t ) );
  append_back_buffer( data, sizeof( openflow_service_header_t ) );

  handle_switch_events( MESSENGER_OPENFLOW_CONNECTED, data->data, data->length );

  stat_entry *stat = lookup_hash_entry( stats, "openflow_application_interface.switch_connected_receive_succeeded" );
  assert_int_equal( ( int ) stat->value, 1 );

  free_buffer( data );
  xfree( delete_hash_entry( stats, "openflow_application_interface.switch_connected_receive_succeeded" ) );
}


static void
test_handle_switch_events_if_type_is_MESSENGER_OPENFLOW_DISCONNECTED() {
  uint64_t *datapath_id;
  buffer *data;

  data = alloc_buffer_with_length( sizeof( openflow_service_header_t ) );
  datapath_id = append_back_buffer( data, sizeof( openflow_service_header_t ) );

  *datapath_id = htonll( DATAPATH_ID );

  expect_memory( mock_switch_disconnected_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_value( mock_switch_disconnected_handler, user_data, SWITCH_DISCONNECTED_USER_DATA );

  expect_string( mock_clear_send_queue, service_name, REMOTE_SERVICE_NAME );
  will_return( mock_clear_send_queue, true );

  set_switch_disconnected_handler( mock_switch_disconnected_handler, SWITCH_DISCONNECTED_USER_DATA );
  handle_switch_events( MESSENGER_OPENFLOW_DISCONNECTED, data->data, data->length );

  stat_entry *stat = lookup_hash_entry( stats, "openflow_application_interface.switch_disconnected_receive_succeeded" );
  assert_int_equal( ( int ) stat->value, 1 );

  free_buffer( data );
  xfree( delete_hash_entry( stats, "openflow_application_interface.switch_disconnected_receive_succeeded" ) );
}


static void
test_handle_switch_events_if_message_is_NULL() {
  expect_assert_failure( handle_switch_events( MESSENGER_OPENFLOW_READY, NULL, 1 ) );
}


static void
test_handle_switch_events_if_message_length_is_zero() {
  buffer *data;

  data = alloc_buffer_with_length( sizeof( openflow_service_header_t ) );

  expect_assert_failure( handle_switch_events( MESSENGER_OPENFLOW_READY, data->data, 0 ) );

  free_buffer( data );
}


static void
test_handle_switch_events_if_message_length_is_too_big() {
  buffer *data;

  data = alloc_buffer_with_length( sizeof( openflow_service_header_t ) );

  expect_assert_failure( handle_switch_events( MESSENGER_OPENFLOW_READY, data->data,
                                               data->length + 1 ) );

  free_buffer( data );
}


static void
test_handle_switch_events_if_unhandled_message_type() {
  buffer *data;

  data = alloc_buffer_with_length( sizeof( openflow_service_header_t ) );
  append_back_buffer( data, sizeof( openflow_service_header_t ) );

  // FIXME
  handle_switch_events( MESSENGER_OPENFLOW_MESSAGE, data->data, data->length );

  stat_entry *stat = lookup_hash_entry( stats, "openflow_application_interface.undefined_switch_event_receive_succeeded" );
  assert_int_equal( ( int ) stat->value, 1 );

  free_buffer( data );
  xfree( delete_hash_entry( stats, "openflow_application_interface.undefined_switch_event_receive_succeeded" ) );
}


/********************************************************************************
 * handle_openflow_message() tests.
 ********************************************************************************/

static void
test_handle_openflow_message() {
  openflow_service_header_t messenger_header;
  stat_entry *stat;

  messenger_header.datapath_id = htonll( DATAPATH_ID );
  messenger_header.service_name_length = 0;

  // error
  {
    buffer *buffer, *data;

    data = alloc_buffer_with_length( 16 );
    append_back_buffer( data, 16 );
    memset( data->data, 'a', 16 );

    buffer = create_error( TRANSACTION_ID, OFPET_HELLO_FAILED, OFPHFC_INCOMPATIBLE, data );
    append_front_buffer( buffer, sizeof( openflow_service_header_t ) );
    memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) );
    expect_memory( mock_error_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
    expect_value( mock_error_handler, transaction_id, TRANSACTION_ID );
    expect_value( mock_error_handler, type32, OFPET_HELLO_FAILED );
    expect_value( mock_error_handler, code32, OFPHFC_INCOMPATIBLE );
    expect_value( mock_error_handler, data->length, data->length );
    expect_memory( mock_error_handler, data->data, data->data, data->length );
    expect_memory( mock_error_handler, user_data, USER_DATA, USER_DATA_LEN );

    set_error_handler( mock_error_handler, USER_DATA );
    handle_openflow_message( buffer->data, buffer->length );

    stat = lookup_hash_entry( stats, "openflow_application_interface.error_receive_succeeded" );
    assert_int_equal( ( int ) stat->value, 1 );

    free_buffer( data );
    free_buffer( buffer );
    xfree( delete_hash_entry( stats, "openflow_application_interface.error_receive_succeeded" ) );
  }
  // experimenter_error
  {
    uint16_t type = OFPET_EXPERIMENTER;

    uint16_t exp_type = 0x3344;
    uint32_t experimenter = 0x55667788;
    buffer *buffer, *data;
    
    data = alloc_buffer_with_length( 16 );
    append_back_buffer( data, 16 );
    memset( data->data, 'a', 16 );

    buffer = create_error_experimenter( TRANSACTION_ID, type, exp_type, experimenter, data );
    append_front_buffer( buffer, sizeof( openflow_service_header_t ) );
    memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) );
    expect_memory( mock_experimenter_error_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
    expect_value( mock_experimenter_error_handler, transaction_id, TRANSACTION_ID );
    expect_value( mock_experimenter_error_handler, type32, ( uint32_t ) type );
    expect_value( mock_experimenter_error_handler, exp_type32, ( uint32_t ) exp_type );
    expect_value( mock_experimenter_error_handler, experimenter, experimenter );
    expect_value( mock_experimenter_error_handler, data->length, data->length );
    expect_memory( mock_experimenter_error_handler, data->data, data->data, data->length );
    expect_memory( mock_experimenter_error_handler, user_data, USER_DATA, USER_DATA_LEN );

    set_experimenter_error_handler( mock_experimenter_error_handler, USER_DATA );
    handle_openflow_message( buffer->data, buffer->length );

    stat = lookup_hash_entry( stats, "openflow_application_interface.error_receive_succeeded" );
    assert_int_equal( ( int ) stat->value, 1 );

    free_buffer( data );
    free_buffer( buffer );
    xfree( delete_hash_entry( stats, "openflow_application_interface.error_receive_succeeded" ) );
  }

  // echo_reply
  {
    buffer *buffer, *data;

    data = alloc_buffer_with_length( 16 );
    append_back_buffer( data, 16 );
    memset( data->data, 'a', 16 );

    buffer = create_echo_reply( TRANSACTION_ID, data );
    append_front_buffer( buffer, sizeof( openflow_service_header_t ) );
    memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) );
    expect_memory( mock_echo_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
    expect_value( mock_echo_reply_handler, transaction_id, TRANSACTION_ID );
    expect_value( mock_echo_reply_handler, data->length, data->length );
    expect_memory( mock_echo_reply_handler, data->data, data->data, data->length );
    expect_memory( mock_echo_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

    set_echo_reply_handler( mock_echo_reply_handler, USER_DATA );
    handle_openflow_message( buffer->data, buffer->length );
    stat = lookup_hash_entry( stats, "openflow_application_interface.echo_reply_receive_succeeded" );
    assert_int_equal( ( int ) stat->value, 1 );

    free_buffer( data );
    free_buffer( buffer );
    xfree( delete_hash_entry( stats, "openflow_application_interface.echo_reply_receive_succeeded" ) );
  }

  // experimenter
  {
    buffer *buffer, *data;
    uint32_t exp_type = 0x1122;

    data = alloc_buffer_with_length( 16 );
    append_back_buffer( data, 16 );
    memset( data->data, 'a', 16 );

    buffer = create_experimenter( TRANSACTION_ID, VENDOR_ID, exp_type, data );
    append_front_buffer( buffer, sizeof( openflow_service_header_t ) );
    memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) );
    expect_memory( mock_experimenter_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
    expect_value( mock_experimenter_handler, transaction_id, TRANSACTION_ID );
    expect_value( mock_experimenter_handler, experimenter, VENDOR_ID );
    expect_value( mock_experimenter_handler, exp_type, exp_type );
    expect_value( mock_experimenter_handler, data->length, data->length );
    expect_memory( mock_experimenter_handler, data->data, data->data, data->length );
    expect_memory( mock_experimenter_handler, user_data, USER_DATA, USER_DATA_LEN );

    set_experimenter_handler( mock_experimenter_handler, USER_DATA );
    handle_openflow_message( buffer->data, buffer->length );

    stat = lookup_hash_entry( stats, "openflow_application_interface.experimenter_receive_succeeded" );
    assert_int_equal( ( int ) stat->value, 1 );

    free_buffer( data );
    free_buffer( buffer );
    xfree( delete_hash_entry( stats, "openflow_application_interface.experimenter_receive_succeeded" ) );
  }

  // features_reply
  {
    uint32_t n_buffers = 1024;
    uint8_t n_tables = 2;
    uint8_t auxiliary_id = 0x11;
    uint32_t capabilities;
    buffer *buffer;

    capabilities = ( OFPC_FLOW_STATS | OFPC_TABLE_STATS | OFPC_PORT_STATS |
                     OFPC_GROUP_STATS | OFPC_IP_REASM | OFPC_QUEUE_STATS | OFPC_PORT_BLOCKED );

    buffer = create_features_reply( TRANSACTION_ID, DATAPATH_ID, n_buffers, n_tables,
                                    auxiliary_id, capabilities );
    append_front_buffer( buffer, sizeof( openflow_service_header_t ) );
    memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) );
    expect_memory( mock_features_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
    expect_value( mock_features_reply_handler, transaction_id, TRANSACTION_ID );
    expect_value( mock_features_reply_handler, n_buffers, n_buffers );
    expect_value( mock_features_reply_handler, n_tables32, ( uint32_t ) n_tables );
    expect_value( mock_features_reply_handler, auxiliary_id32, ( uint32_t ) auxiliary_id );
    expect_value( mock_features_reply_handler, capabilities, capabilities );
    expect_memory( mock_features_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

    set_features_reply_handler( mock_features_reply_handler, USER_DATA );
    handle_openflow_message( buffer->data, buffer->length );

    stat = lookup_hash_entry( stats, "openflow_application_interface.features_reply_receive_succeeded" );
    assert_int_equal( ( int ) stat->value, 1 );
    
    free_buffer( buffer );
    xfree( delete_hash_entry( stats, "openflow_application_interface.features_reply_receive_succeeded" ) );
  }

  // get_config_reply
  {
    uint16_t flags = OFPC_FRAG_NORMAL;
    uint16_t miss_send_len = 128;
    buffer *buffer;

    buffer = create_get_config_reply( TRANSACTION_ID, flags, miss_send_len );
    append_front_buffer( buffer, sizeof( openflow_service_header_t ) );
    memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) );
    expect_memory( mock_get_config_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
    expect_value( mock_get_config_reply_handler, transaction_id, TRANSACTION_ID );
    expect_value( mock_get_config_reply_handler, flags32, ( uint32_t ) flags );
    expect_value( mock_get_config_reply_handler, miss_send_len32, ( uint32_t ) miss_send_len );
    expect_memory( mock_get_config_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

    set_get_config_reply_handler( mock_get_config_reply_handler, USER_DATA );
    handle_openflow_message( buffer->data, buffer->length );

    stat = lookup_hash_entry( stats, "openflow_application_interface.get_config_reply_receive_succeeded" );
    assert_int_equal( ( int ) stat->value, 1 );

    free_buffer( buffer );
    xfree( delete_hash_entry( stats, "openflow_application_interface.get_config_reply_receive_succeeded" ) );
  }

  // packet_in
  {
    uint32_t buffer_id = 0x01020304;
    uint8_t reason = OFPR_NO_MATCH;
    uint8_t table_id = 0x01;
    uint64_t cookie = 0xAAAABBBBCCCCDDDD;
    oxm_matches *match;
    size_t match1_len, match2_len;
    oxm_match_header *queue[ 2 ];
    uint32_t* value;

    match1_len = ( sizeof( oxm_match_header ) + OXM_LENGTH( OXM_OF_IN_PORT ) );
    queue[ 0 ] = xcalloc( 1, match1_len );
    value = ( uint32_t* ) (queue[ 0 ] + 1);
    *queue[ 0 ] = OXM_OF_IN_PORT;
    *value = 0x2468ACEF;

    match2_len = ( sizeof( oxm_match_header ) + OXM_LENGTH( OXM_OF_IN_PHY_PORT ) );
    queue[ 1 ] = xcalloc( 1, match2_len );
    value = ( uint32_t* ) (queue[ 1 ] + 1);
    *queue[ 1 ] = OXM_OF_IN_PHY_PORT;
    *value = 0xFECA8642;

    match = create_oxm_matches();
    match->n_matches = 2;
    append_to_tail( &match->list, queue[ 0 ] );
    append_to_tail( &match->list, queue[ 1 ] );

    buffer *data = alloc_buffer_with_length( 64 );
    calloc_packet_info( data );
    append_back_buffer( data, 64 );
    memset( data->data, 0x01, 64 );
    uint16_t total_len = ( uint16_t ) data->length ;

    buffer *buffer = create_packet_in( TRANSACTION_ID, buffer_id, total_len, reason, table_id, cookie, match, data );
    append_front_buffer( buffer, sizeof( openflow_service_header_t ) );
    memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) );
    will_return( mock_parse_packet, true );
    expect_memory( mock_packet_in_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
    expect_value( mock_packet_in_handler, transaction_id, TRANSACTION_ID );
    expect_value( mock_packet_in_handler, buffer_id, buffer_id );
    expect_value( mock_packet_in_handler, total_len32, ( uint32_t ) total_len );
    expect_value( mock_packet_in_handler, reason32, ( uint32_t ) reason );
    expect_value( mock_packet_in_handler, table_id32, ( uint32_t ) table_id );
    expect_memory( mock_packet_in_handler, &cookie, &cookie, sizeof( uint64_t ) );
    expect_memory( mock_packet_in_handler, match1, queue[ 0 ], match1_len );
    expect_memory( mock_packet_in_handler, match2, queue[ 1 ], match2_len );
    expect_value( mock_packet_in_handler, data->length, data->length );
    expect_memory( mock_packet_in_handler, data->data, data->data, data->length );
    expect_memory( mock_packet_in_handler, user_data, USER_DATA, USER_DATA_LEN );

    set_packet_in_handler( mock_packet_in_handler, USER_DATA );
    handle_openflow_message( buffer->data, buffer->length );

    stat = lookup_hash_entry( stats, "openflow_application_interface.packet_in_receive_succeeded" );
    assert_int_equal( ( int ) stat->value, 1 );

    delete_oxm_matches(match);
    free_buffer( buffer );
    free_buffer( data );
    xfree( delete_hash_entry( stats, "openflow_application_interface.packet_in_receive_succeeded" ) );
  }

  // flow_removed
  {
    uint64_t cookie = 0x1111222233334444;
    uint16_t priority = OFP_HIGH_PRIORITY;
    uint8_t reason =  OFPRR_IDLE_TIMEOUT;
    uint8_t table_id = 0xAA;
    uint32_t duration_sec = 180;
    uint32_t duration_nsec = 10000;
    uint16_t idle_timeout = 60;
    uint16_t hard_timeout = 120;
    uint64_t packet_count = 1000;
    uint64_t byte_count = 100000;
    oxm_matches *match;
    size_t match1_len, match2_len;
    oxm_match_header *queue[ 2 ];
    uint32_t* value;
    
    match1_len = ( sizeof( oxm_match_header ) + OXM_LENGTH( OXM_OF_IN_PORT ) );
    queue[ 0 ] = xcalloc( 1, match1_len );
    value = ( uint32_t* ) (queue[ 0 ] + 1);
    *queue[ 0 ] = OXM_OF_IN_PORT;
    *value = 0x2468ACEF;
      
    match2_len = ( sizeof( oxm_match_header ) + OXM_LENGTH( OXM_OF_IN_PHY_PORT ) );
    queue[ 1 ] = xcalloc( 1, match2_len );
    value = ( uint32_t* ) (queue[ 1 ] + 1);
    *queue[ 1 ] = OXM_OF_IN_PHY_PORT;
    *value = 0xFECA8642;

    match = create_oxm_matches();
    match->n_matches = 2;
    append_to_tail( &match->list, queue[ 0 ] );
    append_to_tail( &match->list, queue[ 1 ] );

    buffer *buffer = create_flow_removed(
      TRANSACTION_ID,
      cookie,
      priority,
      reason,
      table_id,
      duration_sec,
      duration_nsec,
      idle_timeout,
      hard_timeout,
      packet_count,
      byte_count,
      match
    );
    append_front_buffer( buffer, sizeof( openflow_service_header_t ) );
    memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) );
    expect_memory( mock_flow_removed_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
    expect_value( mock_flow_removed_handler, transaction_id, TRANSACTION_ID );
    expect_memory( mock_flow_removed_handler, &cookie, &cookie, sizeof( uint64_t ) );
    expect_value( mock_flow_removed_handler, priority32, ( uint32_t ) priority );
    expect_value( mock_flow_removed_handler, reason32, ( uint32_t ) reason );
    expect_value( mock_flow_removed_handler, table_id32, ( uint32_t ) table_id );
    expect_value( mock_flow_removed_handler, duration_sec, duration_sec );
    expect_value( mock_flow_removed_handler, duration_nsec, duration_nsec );
    expect_value( mock_flow_removed_handler, idle_timeout32, ( uint32_t ) idle_timeout );
    expect_value( mock_flow_removed_handler, hard_timeout32, ( uint32_t ) hard_timeout );
    expect_memory( mock_flow_removed_handler, &packet_count, &packet_count, sizeof( uint64_t ) );
    expect_memory( mock_flow_removed_handler, &byte_count, &byte_count, sizeof( uint64_t ) );
    expect_memory( mock_flow_removed_handler, match1, queue[ 0 ], match1_len );
    expect_memory( mock_flow_removed_handler, match2, queue[ 1 ], match2_len );
    expect_memory( mock_flow_removed_handler, user_data, USER_DATA, USER_DATA_LEN );

    set_flow_removed_handler( mock_flow_removed_handler, USER_DATA );
    handle_openflow_message( buffer->data, buffer->length );

    stat = lookup_hash_entry( stats, "openflow_application_interface.flow_removed_receive_succeeded" );
    assert_int_equal( ( int ) stat->value, 1 );

    delete_oxm_matches(match);
    free_buffer( buffer );
    xfree( delete_hash_entry( stats, "openflow_application_interface.flow_removed_receive_succeeded" ) );
  }

  // port_status
  {
    uint8_t reason = OFPPR_MODIFY;
    buffer *buffer;
    struct ofp_port desc;

    desc.port_no = 1;
    memset( desc.pad, 0, sizeof( desc.pad ) );
    memcpy( desc.hw_addr, MAC_ADDR_X, sizeof( desc.hw_addr ) );
    memset( desc.pad2, 0, sizeof( desc.pad2 ) );
    memset( desc.name, '\0', OFP_MAX_PORT_NAME_LEN );
    memcpy( desc.name, PORT_NAME, strlen( PORT_NAME ) );
    desc.config = OFPPC_PORT_DOWN;
    desc.state = OFPPS_LINK_DOWN;
    desc.curr = ( OFPPF_1GB_FD | OFPPF_COPPER | OFPPF_PAUSE );
    desc.advertised = PORT_FEATURES;
    desc.supported = PORT_FEATURES;
    desc.peer = PORT_FEATURES;
    desc.curr_speed = 0x1024;
    desc.max_speed = 0x2048;

    buffer = create_port_status( TRANSACTION_ID, reason, desc );
    append_front_buffer( buffer, sizeof( openflow_service_header_t ) );
    memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) );
    expect_memory( mock_port_status_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
    expect_value( mock_port_status_handler, transaction_id, TRANSACTION_ID );
    expect_value( mock_port_status_handler, reason32, ( uint32_t ) reason );
    expect_memory( mock_port_status_handler, &desc, &desc, sizeof( struct ofp_port ) );
    expect_memory( mock_port_status_handler, user_data, USER_DATA, USER_DATA_LEN );

    set_port_status_handler( mock_port_status_handler, USER_DATA );
    handle_openflow_message( buffer->data, buffer->length );

    stat = lookup_hash_entry( stats, "openflow_application_interface.port_status_receive_succeeded" );
    assert_int_equal( ( int ) stat->value, 1 );

    free_buffer( buffer );
    xfree( delete_hash_entry( stats, "openflow_application_interface.port_status_receive_succeeded" ) );
  }

  // multipart_reply
  {
    char mfr_desc[ DESC_STR_LEN ];
    char hw_desc[ DESC_STR_LEN ];
    char sw_desc[ DESC_STR_LEN ];
    char serial_num[ SERIAL_NUM_LEN ];
    char dp_desc[ DESC_STR_LEN ];
    uint16_t flags = 0;
    uint32_t body_len;
    buffer *buffer;
    struct ofp_multipart_reply *multipart_reply;

    memset( mfr_desc, '\0', DESC_STR_LEN );
    memset( hw_desc, '\0', DESC_STR_LEN );
    memset( sw_desc, '\0', DESC_STR_LEN );
    memset( serial_num, '\0', SERIAL_NUM_LEN );
    memset( dp_desc, '\0', DESC_STR_LEN );
    sprintf( mfr_desc, "NEC Coporation" );
    sprintf( hw_desc, "OpenFlow Switch Hardware" );
    sprintf( sw_desc, "OpenFlow Switch Software" );
    sprintf( serial_num, "123456" );
    sprintf( dp_desc, "Datapath 0" );

    buffer = create_desc_multipart_reply( TRANSACTION_ID, flags, mfr_desc, hw_desc,
                                      sw_desc, serial_num, dp_desc );
    append_front_buffer( buffer, sizeof( openflow_service_header_t ) );
    memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) );
    multipart_reply = ( struct ofp_multipart_reply * ) ( ( char * ) buffer->data + sizeof( openflow_service_header_t ) );
    body_len = ( uint32_t ) ( ntohs( multipart_reply->header.length ) -
                              offsetof( struct ofp_multipart_reply, body ) );

    expect_memory( mock_multipart_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
    expect_value( mock_multipart_reply_handler, transaction_id, TRANSACTION_ID );
    expect_value( mock_multipart_reply_handler, type32, OFPMP_DESC );
    expect_value( mock_multipart_reply_handler, flags32, ( uint32_t ) flags );
    expect_value( mock_multipart_reply_handler, data->length, body_len );
    expect_memory( mock_multipart_reply_handler, data->data, multipart_reply->body, body_len );
    expect_memory( mock_multipart_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

    set_multipart_reply_handler( mock_multipart_reply_handler, USER_DATA );
    handle_openflow_message( buffer->data, buffer->length );

    stat = lookup_hash_entry( stats, "openflow_application_interface.multipart_reply_receive_succeeded" );
    assert_int_equal( ( int ) stat->value, 1 );

    free_buffer( buffer );
    xfree( delete_hash_entry( stats, "openflow_application_interface.multipart_reply_receive_succeeded" ) );
  }

  {
    void *expected_data;
    uint16_t flags = OFPMPF_REPLY_MORE;
    list_element *expected_list;
    buffer *buffer;
    uint16_t stats_len = 0;
    uint32_t body_len;
    struct ofp_multipart_reply *multipart_reply;
    struct ofp_flow_stats *expected_stats[ 2 ];
    struct ofp_instruction *inst;

    // with match
    {
      create_oxm_match_testdata();
      create_instruction_testdata();

      stats_len = ( uint16_t ) ( offsetof( struct ofp_flow_stats, match ) + expected_ofp_match_len + expected_ofp_instruction_len );

      expected_stats[ 0 ] = xcalloc( 1, stats_len );
      expected_stats[ 1 ] = xcalloc( 1, stats_len );

      expected_stats[ 0 ]->length = stats_len;
      expected_stats[ 0 ]->table_id = 1;
      expected_stats[ 0 ]->pad = 0;
      expected_stats[ 0 ]->duration_sec = 60;
      expected_stats[ 0 ]->duration_nsec = 10000;
      expected_stats[ 0 ]->priority = 1024;
      expected_stats[ 0 ]->idle_timeout = 60;
      expected_stats[ 0 ]->hard_timeout = 3600;
      expected_stats[ 0 ]->flags = OFPFF_NO_BYT_COUNTS;
      memset( expected_stats[ 0 ]->pad2, 0, sizeof( expected_stats[ 0 ]->pad2 ) );
      expected_stats[ 0 ]->cookie = 0x0102030405060708ULL;
      expected_stats[ 0 ]->packet_count = 1000;
      expected_stats[ 0 ]->byte_count = 100000;
      memcpy( &expected_stats[ 0 ]->match, expected_ofp_match, expected_ofp_match_len );
      inst = ( struct ofp_instruction * ) ( ( char * ) &expected_stats[ 0 ]->match + expected_ofp_match_len );
      memcpy( inst, expected_ofp_instruction, expected_ofp_instruction_len );

      memcpy( expected_stats[ 1 ], expected_stats[ 0 ], stats_len );
      expected_stats[ 1 ]->cookie = 0x0203040506070809ULL;

      create_list( &expected_list );
      append_to_tail( &expected_list, expected_stats[ 0 ] );
      append_to_tail( &expected_list, expected_stats[ 1 ] );

      expected_data = xcalloc( 1, ( size_t ) ( stats_len * 2 ) );
      memcpy( expected_data, expected_stats[ 0 ], stats_len );
      memcpy( ( char * ) expected_data + stats_len, expected_stats[ 1 ], stats_len );

      buffer = create_flow_multipart_reply( TRANSACTION_ID, flags, expected_list );
      append_front_buffer( buffer, sizeof( openflow_service_header_t ) );
      memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) );
      multipart_reply = ( struct ofp_multipart_reply * ) ( ( char * ) buffer->data + sizeof( openflow_service_header_t ) );
      body_len = ( uint32_t ) ( ntohs( multipart_reply->header.length ) -
                                offsetof( struct ofp_multipart_reply, body ) );

      expect_memory( mock_multipart_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
      expect_value( mock_multipart_reply_handler, transaction_id, TRANSACTION_ID );
      expect_value( mock_multipart_reply_handler, type32, OFPMP_FLOW );
      expect_value( mock_multipart_reply_handler, flags32, ( uint32_t ) flags );
      expect_value( mock_multipart_reply_handler, data->length, body_len );
      expect_memory( mock_multipart_reply_handler, data->data, expected_data, stats_len );
      expect_memory( mock_multipart_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

      set_multipart_reply_handler( mock_multipart_reply_handler, USER_DATA );
      handle_openflow_message( buffer->data, buffer->length );

      stat = lookup_hash_entry( stats, "openflow_application_interface.multipart_reply_receive_succeeded" );
      assert_int_equal( ( int ) stat->value, 1 );

      xfree( expected_stats[ 0 ] );
      xfree( expected_stats[ 1 ] );
      delete_list( expected_list );

      delete_oxm_match_testdata();
      delete_instruction_testdata();
      free_buffer( buffer );
      xfree( expected_data );
      xfree( delete_hash_entry( stats, "openflow_application_interface.multipart_reply_receive_succeeded" ) );
    }
  }
  {
    uint16_t flags = 0;
    uint32_t body_len;
    uint32_t flow_count = 1000;
    uint64_t packet_count = 1000;
    uint64_t byte_count = 10000;
    buffer *buffer;
    struct ofp_multipart_reply *multipart_reply;
    struct ofp_aggregate_stats_reply aggregate_multipart_reply;

    buffer = create_aggregate_multipart_reply( TRANSACTION_ID, flags, packet_count,
                                               byte_count, flow_count );
    append_front_buffer( buffer, sizeof( openflow_service_header_t ) );
    memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) );

    multipart_reply = ( struct ofp_multipart_reply * ) ( ( char * ) buffer->data + sizeof( openflow_service_header_t ) );
    body_len = ( uint32_t ) ( ntohs( multipart_reply->header.length ) -
                              offsetof( struct ofp_multipart_reply, body ) );

    expect_memory( mock_multipart_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
    expect_value( mock_multipart_reply_handler, transaction_id, TRANSACTION_ID );
    expect_value( mock_multipart_reply_handler, type32, OFPMP_AGGREGATE );
    expect_value( mock_multipart_reply_handler, flags32, ( uint32_t ) flags );
    expect_value( mock_multipart_reply_handler, data->length, body_len );
    ntoh_aggregate_stats( &aggregate_multipart_reply,
                          ( struct ofp_aggregate_stats_reply * ) multipart_reply->body );
    expect_memory( mock_multipart_reply_handler, data->data, &aggregate_multipart_reply, body_len );
    expect_memory( mock_multipart_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

    set_multipart_reply_handler( mock_multipart_reply_handler, USER_DATA );
    handle_openflow_message( buffer->data, buffer->length );

    stat = lookup_hash_entry( stats, "openflow_application_interface.multipart_reply_receive_succeeded" );
    assert_int_equal( ( int ) stat->value, 1 );

    free_buffer( buffer );
    xfree( delete_hash_entry( stats, "openflow_application_interface.multipart_reply_receive_succeeded" ) );
  }
  {
    void *expected_data;
    uint16_t flags = OFPMPF_REPLY_MORE;
    uint16_t stats_len;
    uint32_t body_len;
    buffer *buffer;
    list_element *table_stats;
    struct ofp_multipart_reply *multipart_reply;
    struct ofp_table_stats *tb_stats[ 2 ];

    stats_len = sizeof( struct ofp_table_stats );

    tb_stats[ 0 ] = xcalloc( 1, stats_len );
    tb_stats[ 1 ] = xcalloc( 1, stats_len );

    tb_stats[ 0 ]->table_id = 1;
    memset( tb_stats[ 0 ]->pad, 0, sizeof( tb_stats[ 0 ]->pad ));
    tb_stats[ 0 ]->active_count = 1000;
    tb_stats[ 0 ]->lookup_count = 100000;
    tb_stats[ 0 ]->matched_count = 10000;

    memcpy( tb_stats[ 1 ], tb_stats[ 0 ], stats_len );
    tb_stats[ 1 ]->table_id = 2;

    create_list( &table_stats );
    append_to_tail( &table_stats, tb_stats[ 0 ] );
    append_to_tail( &table_stats, tb_stats[ 1 ] );

    expected_data = xcalloc( 1, ( size_t ) ( stats_len * 2 ) );
    memcpy( expected_data, tb_stats[ 0 ], stats_len );
    memcpy( ( char * ) expected_data + stats_len, tb_stats[ 1 ], stats_len );

    buffer = create_table_multipart_reply( TRANSACTION_ID, flags, table_stats );
    append_front_buffer( buffer, sizeof( openflow_service_header_t ) );
    memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) );

    multipart_reply = ( struct ofp_multipart_reply * ) ( ( char * ) buffer->data + sizeof( openflow_service_header_t ) );
    body_len = ( uint32_t ) ( ntohs( multipart_reply->header.length ) -
                              offsetof( struct ofp_multipart_reply, body ) );

    expect_memory( mock_multipart_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
    expect_value( mock_multipart_reply_handler, transaction_id, TRANSACTION_ID );
    expect_value( mock_multipart_reply_handler, type32, OFPMP_TABLE );
    expect_value( mock_multipart_reply_handler, flags32, ( uint32_t ) flags );
    expect_value( mock_multipart_reply_handler, data->length, body_len );
    expect_memory( mock_multipart_reply_handler, data->data, expected_data, stats_len );
    expect_memory( mock_multipart_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

    set_multipart_reply_handler( mock_multipart_reply_handler, USER_DATA );
    handle_openflow_message( buffer->data, buffer->length );

    stat = lookup_hash_entry( stats, "openflow_application_interface.multipart_reply_receive_succeeded" );
    assert_int_equal( ( int ) stat->value, 1 );

    xfree( tb_stats[ 0 ] );
    xfree( tb_stats[ 1 ] );
    delete_list( table_stats );
    xfree( expected_data );
    free_buffer( buffer );
    xfree( delete_hash_entry( stats, "openflow_application_interface.multipart_reply_receive_succeeded" ) );
  }
  {
    void *expected_data;
    uint16_t flags = OFPMPF_REPLY_MORE;
    uint16_t stats_len;
    uint32_t body_len;
    buffer *buffer;
    list_element *port_stats;
    struct ofp_multipart_reply *multipart_reply;
    struct ofp_port_stats *op_port_stats[ 2 ];

    stats_len = sizeof( struct ofp_port_stats );

    op_port_stats[ 0 ] = xcalloc( 1, stats_len );
    op_port_stats[ 1 ] = xcalloc( 1, stats_len );

    op_port_stats[ 0 ]->port_no = 1;
    memset( op_port_stats[ 0 ]->pad, 0, sizeof( op_port_stats[ 0 ]->pad ));
    op_port_stats[ 0 ]->rx_packets = 10000;
    op_port_stats[ 0 ]->tx_packets = 20000;
    op_port_stats[ 0 ]->rx_bytes = 30000;
    op_port_stats[ 0 ]->tx_bytes = 40000;
    op_port_stats[ 0 ]->rx_dropped = 50000;
    op_port_stats[ 0 ]->tx_dropped = 60000;
    op_port_stats[ 0 ]->rx_errors = 70000;
    op_port_stats[ 0 ]->tx_errors = 80000;
    op_port_stats[ 0 ]->rx_frame_err = 1;
    op_port_stats[ 0 ]->rx_over_err = 2;
    op_port_stats[ 0 ]->rx_crc_err = 1;
    op_port_stats[ 0 ]->collisions = 3;
    op_port_stats[ 0 ]->duration_sec = 10;
    op_port_stats[ 0 ]->duration_nsec = 100;

    memcpy( op_port_stats[ 1 ], op_port_stats[ 0 ], stats_len );
    op_port_stats[ 1 ]->port_no = 2;

    create_list( &port_stats );
    append_to_tail( &port_stats, op_port_stats[ 0 ] );
    append_to_tail( &port_stats, op_port_stats[ 1 ] );

    expected_data = xcalloc( 1, ( size_t ) ( stats_len * 2 ) );
    memcpy( expected_data, op_port_stats[ 0 ], stats_len );
    memcpy( ( char * ) expected_data + stats_len, op_port_stats[ 1 ], stats_len );

    buffer = create_port_multipart_reply( TRANSACTION_ID, flags, port_stats );
    append_front_buffer( buffer, sizeof( openflow_service_header_t ) );
    memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) );

    multipart_reply = ( struct ofp_multipart_reply * ) ( ( char * ) buffer->data + sizeof( openflow_service_header_t ) );
    body_len = ( uint32_t ) ( ntohs( multipart_reply->header.length ) -
                              offsetof( struct ofp_multipart_reply, body ) );

    expect_memory( mock_multipart_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
    expect_value( mock_multipart_reply_handler, transaction_id, TRANSACTION_ID );
    expect_value( mock_multipart_reply_handler, type32, OFPMP_PORT_STATS );
    expect_value( mock_multipart_reply_handler, flags32, ( uint32_t ) flags );
    expect_value( mock_multipart_reply_handler, data->length, body_len );
    expect_memory( mock_multipart_reply_handler, data->data, expected_data, stats_len );
    expect_memory( mock_multipart_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

    set_multipart_reply_handler( mock_multipart_reply_handler, USER_DATA );
    handle_openflow_message( buffer->data, buffer->length );

    stat = lookup_hash_entry( stats, "openflow_application_interface.multipart_reply_receive_succeeded" );
    assert_int_equal( ( int ) stat->value, 1 );

    xfree( op_port_stats[ 0 ] );
    xfree( op_port_stats[ 1 ] );
    delete_list( port_stats );
    xfree( expected_data );
    free_buffer( buffer );
    xfree( delete_hash_entry( stats, "openflow_application_interface.multipart_reply_receive_succeeded" ) );
  }
  {
    void *expected_data;
    uint16_t flags = OFPMPF_REPLY_MORE;
    uint16_t stats_len;
    uint32_t body_len;
    buffer *buffer;
    list_element *queue_stats;
    struct ofp_multipart_reply *multipart_reply;
    struct ofp_queue_stats *op_queue_stats[ 2 ];

    stats_len = sizeof( struct ofp_queue_stats );

    op_queue_stats[ 0 ] = xcalloc( 1, stats_len );
    op_queue_stats[ 1 ] = xcalloc( 1, stats_len );

    op_queue_stats[ 0 ]->port_no = 1;
    op_queue_stats[ 0 ]->queue_id = 2;
    op_queue_stats[ 0 ]->tx_bytes = 100000;
    op_queue_stats[ 0 ]->tx_packets = 60000;
    op_queue_stats[ 0 ]->tx_errors = 80;
    op_queue_stats[ 0 ]->duration_sec = 10;
    op_queue_stats[ 0 ]->duration_nsec = 100;

    memcpy( op_queue_stats[ 1 ], op_queue_stats[ 0 ], stats_len );
    op_queue_stats[ 1 ]->queue_id = 3;

    create_list( &queue_stats );
    append_to_tail( &queue_stats, op_queue_stats[ 0 ] );
    append_to_tail( &queue_stats, op_queue_stats[ 1 ] );

    expected_data = xcalloc( 1, ( size_t ) ( stats_len * 2 ) );
    memcpy( expected_data, op_queue_stats[ 0 ], stats_len );
    memcpy( ( char * ) expected_data + stats_len, op_queue_stats[ 1 ], stats_len );

    buffer = create_queue_multipart_reply( TRANSACTION_ID, flags, queue_stats );
    append_front_buffer( buffer, sizeof( openflow_service_header_t ) );
    memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) );
    multipart_reply = ( struct ofp_multipart_reply * ) ( ( char * ) buffer->data + sizeof( openflow_service_header_t ) );
    body_len = ( uint32_t ) ( ntohs( multipart_reply->header.length ) -
                              offsetof( struct ofp_multipart_reply, body ) );

    expect_memory( mock_multipart_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
    expect_value( mock_multipart_reply_handler, transaction_id, TRANSACTION_ID );
    expect_value( mock_multipart_reply_handler, type32, OFPMP_QUEUE );
    expect_value( mock_multipart_reply_handler, flags32, ( uint32_t ) flags );
    expect_value( mock_multipart_reply_handler, data->length, body_len );
    expect_memory( mock_multipart_reply_handler, data->data, expected_data, stats_len );
    expect_memory( mock_multipart_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

    set_multipart_reply_handler( mock_multipart_reply_handler, USER_DATA );
    handle_openflow_message( buffer->data, buffer->length );

    stat = lookup_hash_entry( stats, "openflow_application_interface.multipart_reply_receive_succeeded" );
    assert_int_equal( ( int ) stat->value, 1 );

    xfree( op_queue_stats[ 0 ] );
    xfree( op_queue_stats[ 1 ] );
    delete_list( queue_stats );
    xfree( expected_data );
    free_buffer( buffer );
    xfree( delete_hash_entry( stats, "openflow_application_interface.multipart_reply_receive_succeeded" ) );
  }
  {
    void *expected_data;
    uint16_t flags = OFPMPF_REPLY_MORE;
    uint16_t stats_len;
    uint32_t body_len;
    size_t grpsts_0len, grpsts_1len;
    list_element *list;
    buffer *buffer;
    struct ofp_group_stats *grpsts[ 2 ];
    struct ofp_bucket_counter *bktcnt;
    struct ofp_multipart_reply *multipart_reply;

    grpsts_0len = offsetof( struct ofp_group_stats, bucket_stats ) + sizeof( struct ofp_bucket_counter );
    grpsts_1len = offsetof( struct ofp_group_stats, bucket_stats ) + sizeof( struct ofp_bucket_counter );

    stats_len = ( uint16_t ) ( grpsts_0len + grpsts_1len );

    grpsts[ 0 ] = xcalloc( 1, grpsts_0len );
    grpsts[ 1 ] = xcalloc( 1, grpsts_1len );

    grpsts[ 0 ]->length = ( uint16_t ) grpsts_0len;
    grpsts[ 0 ]->group_id = 1;
    grpsts[ 0 ]->ref_count = 2;
    grpsts[ 0 ]->packet_count = 3;
    grpsts[ 0 ]->byte_count = 4;
    grpsts[ 0 ]->duration_sec = 5;
    grpsts[ 0 ]->duration_nsec = 6;
    bktcnt = ( struct ofp_bucket_counter * ) grpsts[ 0 ]->bucket_stats;
    bktcnt->packet_count = 7;
    bktcnt->byte_count = 8;

    grpsts[ 1 ]->length = ( uint16_t ) grpsts_1len;
    grpsts[ 1 ]->group_id = 11;
    grpsts[ 1 ]->ref_count = 12;
    grpsts[ 1 ]->packet_count = 13;
    grpsts[ 1 ]->byte_count = 14;
    grpsts[ 1 ]->duration_sec = 15;
    grpsts[ 1 ]->duration_nsec = 16;
    bktcnt = ( struct ofp_bucket_counter * ) grpsts[ 1 ]->bucket_stats;
    bktcnt->packet_count = 17;
    bktcnt->byte_count = 18;

    create_list( &list );
    append_to_tail( &list, grpsts[ 0 ] );
    append_to_tail( &list, grpsts[ 1 ] );

    expected_data = xcalloc( 1, ( size_t ) ( grpsts_0len + grpsts_1len ) );
    memcpy( expected_data, grpsts[ 0 ], grpsts_0len );
    memcpy( ( char * ) expected_data + grpsts_0len, grpsts[ 1 ], grpsts_1len );

    buffer = create_group_multipart_reply( TRANSACTION_ID, flags, list );
    append_front_buffer( buffer, sizeof( openflow_service_header_t ) );
    memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) );
    multipart_reply = ( struct ofp_multipart_reply * ) ( ( char * ) buffer->data + sizeof( openflow_service_header_t ) );
    body_len = ( uint32_t ) ( ntohs( multipart_reply->header.length ) -
                              offsetof( struct ofp_multipart_reply, body ) );

    expect_memory( mock_multipart_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
    expect_value( mock_multipart_reply_handler, transaction_id, TRANSACTION_ID );
    expect_value( mock_multipart_reply_handler, type32, OFPMP_GROUP );
    expect_value( mock_multipart_reply_handler, flags32, ( uint32_t ) flags );
    expect_value( mock_multipart_reply_handler, data->length, body_len );
    expect_memory( mock_multipart_reply_handler, data->data, expected_data, stats_len );
    expect_memory( mock_multipart_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

    set_multipart_reply_handler( mock_multipart_reply_handler, USER_DATA );
    handle_openflow_message( buffer->data, buffer->length );

    stat = lookup_hash_entry( stats, "openflow_application_interface.multipart_reply_receive_succeeded" );
    assert_int_equal( ( int ) stat->value, 1 );

    xfree( grpsts[ 0 ] );
    xfree( grpsts[ 1 ] );
    delete_list( list );
    xfree( expected_data );
    free_buffer( buffer );
    xfree( delete_hash_entry( stats, "openflow_application_interface.multipart_reply_receive_succeeded" ) );
  }
  {
    void *expected_data;
    uint16_t flags = OFPMPF_REPLY_MORE;
    uint16_t stats_len;
    uint32_t body_len;
    uint16_t grpdsc_len[2];
    buffer *buffer;
    list_element *expected_list;
    struct ofp_group_desc *dsc1, *dsc2;
    struct ofp_multipart_reply *multipart_reply;

    create_bucket_testdata();

    grpdsc_len[0] = ( uint16_t ) ( offsetof( struct ofp_group_desc, buckets ) + bucket_testdata_len[0] );
    dsc1 = xcalloc( 1, grpdsc_len[0] );
    dsc1->length = grpdsc_len[0];
    dsc1->type = OFPGT_SELECT;
    dsc1->group_id = 0x11223344;
    memcpy( dsc1->buckets, bucket_testdata[0], bucket_testdata_len[0] );

    grpdsc_len[1] = ( uint16_t ) ( offsetof( struct ofp_group_desc, buckets ) + bucket_testdata_len[1] );
    dsc2 = xcalloc( 1, grpdsc_len[1] );
    dsc2->length = grpdsc_len[1];
    dsc2->type = OFPGT_INDIRECT;
    dsc2->group_id = 0x55667788;
    memcpy( dsc2->buckets, bucket_testdata[1], bucket_testdata_len[1] );

    stats_len = ( uint16_t ) ( grpdsc_len[0] + grpdsc_len[1] );

    create_list( &expected_list );
    append_to_tail( &expected_list, dsc1 );
    append_to_tail( &expected_list, dsc2 );

    expected_data = xcalloc( 1, ( size_t ) ( stats_len ) );
    memcpy( expected_data, dsc1, grpdsc_len[0] );
    memcpy( ( char * ) expected_data + grpdsc_len[0], dsc2, grpdsc_len[1] );

    buffer = create_group_desc_multipart_reply( TRANSACTION_ID, flags, expected_list );
    append_front_buffer( buffer, sizeof( openflow_service_header_t ) );
    memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) );

    multipart_reply = ( struct ofp_multipart_reply * ) ( ( char * ) buffer->data + sizeof( openflow_service_header_t ) );
    body_len = ( uint32_t ) ( ntohs( multipart_reply->header.length ) -
                              offsetof( struct ofp_multipart_reply, body ) );

    expect_memory( mock_multipart_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
    expect_value( mock_multipart_reply_handler, transaction_id, TRANSACTION_ID );
    expect_value( mock_multipart_reply_handler, type32, OFPMP_GROUP_DESC );
    expect_value( mock_multipart_reply_handler, flags32, ( uint32_t ) flags );
    expect_value( mock_multipart_reply_handler, data->length, body_len );
    expect_memory( mock_multipart_reply_handler, data->data, expected_data, stats_len );
    expect_memory( mock_multipart_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

    set_multipart_reply_handler( mock_multipart_reply_handler, USER_DATA );
    handle_openflow_message( buffer->data, buffer->length );

    stat = lookup_hash_entry( stats, "openflow_application_interface.multipart_reply_receive_succeeded" );
    assert_int_equal( ( int ) stat->value, 1 );

    delete_bucket_testdata();
    xfree( dsc1 );
    xfree( dsc2 );
    delete_list( expected_list );
    xfree( expected_data );
    free_buffer( buffer );
    xfree( delete_hash_entry( stats, "openflow_application_interface.multipart_reply_receive_succeeded" ) );
  }
  {
    void *expected_data;
    uint16_t flags = OFPMPF_REPLY_MORE;
    uint16_t stats_len;
    uint32_t body_len;
    buffer *buffer;
    struct ofp_group_features *grpftr;
    struct ofp_multipart_reply *multipart_reply;

    uint16_t grpftr_len = sizeof( struct ofp_group_features );

    stats_len = grpftr_len;

    grpftr = xcalloc( 1, grpftr_len );
    grpftr->types = OFPGT_SELECT;
    grpftr->capabilities = OFPGFC_CHAINING;
    grpftr->max_groups[0] = 1;
    grpftr->max_groups[1] = 2;
    grpftr->max_groups[2] = 3;
    grpftr->max_groups[3] = 4;
    grpftr->actions[0] = 5;
    grpftr->actions[1] = 6;
    grpftr->actions[2] = 7;
    grpftr->actions[3] = 8;

    buffer = create_group_features_multipart_reply( TRANSACTION_ID, flags, grpftr->types,
      grpftr->capabilities, grpftr->max_groups, grpftr->actions );

    expected_data = grpftr;

    append_front_buffer( buffer, sizeof( openflow_service_header_t ) );
    memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) );
    multipart_reply = ( struct ofp_multipart_reply * ) ( ( char * ) buffer->data + sizeof( openflow_service_header_t ) );
    body_len = ( uint32_t ) ( ntohs( multipart_reply->header.length ) -
                              offsetof( struct ofp_multipart_reply, body ) );

    expect_memory( mock_multipart_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
    expect_value( mock_multipart_reply_handler, transaction_id, TRANSACTION_ID );
    expect_value( mock_multipart_reply_handler, type32, OFPMP_GROUP_FEATURES );
    expect_value( mock_multipart_reply_handler, flags32, ( uint32_t ) flags );
    expect_value( mock_multipart_reply_handler, data->length, body_len );
    expect_memory( mock_multipart_reply_handler, data->data, expected_data, stats_len );
    expect_memory( mock_multipart_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

    set_multipart_reply_handler( mock_multipart_reply_handler, USER_DATA );
    handle_openflow_message( buffer->data, buffer->length );

    stat = lookup_hash_entry( stats, "openflow_application_interface.multipart_reply_receive_succeeded" );
    assert_int_equal( ( int ) stat->value, 1 );

    xfree( expected_data );
    free_buffer( buffer );
    xfree( delete_hash_entry( stats, "openflow_application_interface.multipart_reply_receive_succeeded" ) );
  }
  {
    void *expected_data;
    uint16_t flags = OFPMPF_REPLY_MORE;
    uint16_t stats_len;
    uint32_t body_len;
    uint16_t mtrsts_len[2];
    buffer *buffer;
    list_element *expected_list;
    struct ofp_meter_stats *mtr1, *mtr2;
    struct ofp_meter_band_stats *mtrbnd;
    struct ofp_multipart_reply *multipart_reply;

    mtrsts_len[0] = ( uint16_t ) ( offsetof( struct ofp_meter_stats, band_stats ) + sizeof( struct ofp_meter_band_stats ) );
    mtr1 = xcalloc( 1, mtrsts_len[0] );
    mtr1->meter_id = 0xaabbccdd;
    mtr1->len = mtrsts_len[0];
    mtr1->flow_count = 1;
    mtr1->packet_in_count = 2;
    mtr1->byte_in_count = 3;
    mtr1->duration_sec = 4;
    mtr1->duration_nsec = 5;
    mtrbnd = mtr1->band_stats;
    mtrbnd->packet_band_count = 0x11223344;
    mtrbnd->byte_band_count = 0x55667788;

    mtrsts_len[1] = ( uint16_t ) ( offsetof( struct ofp_meter_stats, band_stats ) + sizeof( struct ofp_meter_band_stats ) );
    mtr2 = xcalloc( 1, mtrsts_len[1] );
    mtr2->meter_id = 0x12345566;
    mtr2->len = mtrsts_len[1];
    mtr2->flow_count = 1;
    mtr2->packet_in_count = 2;
    mtr2->byte_in_count = 3;
    mtr2->duration_sec = 4;
    mtr2->duration_nsec = 5;
    mtrbnd = mtr2->band_stats;
    mtrbnd->packet_band_count = 0x11223344;
    mtrbnd->byte_band_count = 0x55667788;

    stats_len = ( uint16_t ) ( mtrsts_len[0] + mtrsts_len[1] );

    create_list( &expected_list );
    append_to_tail( &expected_list, mtr1 );
    append_to_tail( &expected_list, mtr2 );

    expected_data = xcalloc( 1, ( size_t ) ( stats_len ) );
    memcpy( expected_data, mtr1, mtrsts_len[0] );
    memcpy( ( char * ) expected_data + mtrsts_len[0], mtr2, mtrsts_len[1] );

    buffer = create_meter_multipart_reply( TRANSACTION_ID, flags, expected_list );
    append_front_buffer( buffer, sizeof( openflow_service_header_t ) );
    memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) );
    multipart_reply = ( struct ofp_multipart_reply * ) ( ( char * ) buffer->data + sizeof( openflow_service_header_t ) );
    body_len = ( uint32_t ) ( ntohs( multipart_reply->header.length ) -
                              offsetof( struct ofp_multipart_reply, body ) );

    expect_memory( mock_multipart_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
    expect_value( mock_multipart_reply_handler, transaction_id, TRANSACTION_ID );
    expect_value( mock_multipart_reply_handler, type32, OFPMP_METER );
    expect_value( mock_multipart_reply_handler, flags32, ( uint32_t ) flags );
    expect_value( mock_multipart_reply_handler, data->length, body_len );
    expect_memory( mock_multipart_reply_handler, data->data, expected_data, stats_len );
    expect_memory( mock_multipart_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

    set_multipart_reply_handler( mock_multipart_reply_handler, USER_DATA );
    handle_openflow_message( buffer->data, buffer->length );

    stat = lookup_hash_entry( stats, "openflow_application_interface.multipart_reply_receive_succeeded" );
    assert_int_equal( ( int ) stat->value, 1 );

    xfree( mtr1 );
    xfree( mtr2 );
    delete_list( expected_list );
    xfree( expected_data );
    free_buffer( buffer );
    xfree( delete_hash_entry( stats, "openflow_application_interface.multipart_reply_receive_succeeded" ) );
  }
  {
    void *expected_data;
    uint16_t flags = OFPMPF_REPLY_MORE;
    uint16_t stats_len;
    uint32_t body_len;
    uint16_t mtrcfg_len[2];
    buffer *buffer;
    list_element *expected_list;
    struct ofp_meter_config *mtr1, *mtr2;
    struct ofp_meter_band_drop *mtrbnd;
    struct ofp_multipart_reply *multipart_reply;

    mtrcfg_len[0] = ( uint16_t ) ( offsetof( struct ofp_meter_config, bands ) + sizeof( struct ofp_meter_band_drop ) );
    mtr1 = xcalloc( 1, mtrcfg_len[0] );
    mtr1->length = mtrcfg_len[0];
    mtr1->flags = OFPMC_MODIFY;
    mtr1->meter_id = 1;
    mtrbnd = ( struct ofp_meter_band_drop * ) mtr1->bands;
    mtrbnd->type = OFPMBT_DROP;
    mtrbnd->len = sizeof( struct ofp_meter_band_drop );
    mtrbnd->rate = 0x11223344;
    mtrbnd->burst_size = 0x55667788;

    mtrcfg_len[1] = ( uint16_t ) ( offsetof( struct ofp_meter_config, bands ) + sizeof( struct ofp_meter_band_drop ) );
    mtr2 = xcalloc( 1, mtrcfg_len[1] );
    mtr2->length = mtrcfg_len[1];
    mtr2->flags = OFPMC_DELETE;
    mtr2->meter_id = 1;
    mtrbnd = ( struct ofp_meter_band_drop * ) mtr2->bands;
    mtrbnd->type = OFPMBT_DROP;
    mtrbnd->len = sizeof( struct ofp_meter_band_drop );
    mtrbnd->rate = 0x12345555;
    mtrbnd->burst_size = 0x56789999;

    stats_len = ( uint16_t ) ( mtrcfg_len[0] + mtrcfg_len[1] );

    create_list( &expected_list );
    append_to_tail( &expected_list, mtr1 );
    append_to_tail( &expected_list, mtr2 );

    expected_data = xcalloc( 1, ( size_t ) ( stats_len ) );
    memcpy( expected_data, mtr1, mtrcfg_len[0] );
    memcpy( ( char * ) expected_data + mtrcfg_len[0], mtr2, mtrcfg_len[1] );

    buffer = create_meter_config_multipart_reply( TRANSACTION_ID, flags, expected_list );
    append_front_buffer( buffer, sizeof( openflow_service_header_t ) );
    memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) );
    multipart_reply = ( struct ofp_multipart_reply * ) ( ( char * ) buffer->data + sizeof( openflow_service_header_t ) );
    body_len = ( uint32_t ) ( ntohs( multipart_reply->header.length ) -
                              offsetof( struct ofp_multipart_reply, body ) );

    expect_memory( mock_multipart_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
    expect_value( mock_multipart_reply_handler, transaction_id, TRANSACTION_ID );
    expect_value( mock_multipart_reply_handler, type32, OFPMP_METER_CONFIG );
    expect_value( mock_multipart_reply_handler, flags32, ( uint32_t ) flags );
    expect_value( mock_multipart_reply_handler, data->length, body_len );
    expect_memory( mock_multipart_reply_handler, data->data, expected_data, stats_len );
    expect_memory( mock_multipart_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

    set_multipart_reply_handler( mock_multipart_reply_handler, USER_DATA );
    handle_openflow_message( buffer->data, buffer->length );

    stat = lookup_hash_entry( stats, "openflow_application_interface.multipart_reply_receive_succeeded" );
    assert_int_equal( ( int ) stat->value, 1 );

    xfree( mtr1 );
    xfree( mtr2 );
    delete_list( expected_list );
    xfree( expected_data );
    free_buffer( buffer );
    xfree( delete_hash_entry( stats, "openflow_application_interface.multipart_reply_receive_succeeded" ) );
  }
  {
    void *expected_data;
    uint16_t flags = OFPMPF_REPLY_MORE;
    uint16_t stats_len;
    uint32_t body_len;
    buffer *buffer;
    struct ofp_multipart_reply *multipart_reply;
    struct ofp_meter_features *mtrftr;

    stats_len = sizeof( struct ofp_meter_features );

    mtrftr = xcalloc( 1, stats_len );
    mtrftr->max_meter = 1;
    mtrftr->band_types = ( 1 << OFPMBT_DROP );
    mtrftr->capabilities = ( 1 << OFPMF_KBPS );
    mtrftr->max_bands = 10;
    mtrftr->max_color = 20;
    memset( mtrftr->pad, 0, sizeof( mtrftr->pad ) );

    expected_data = mtrftr;

    buffer = create_meter_features_multipart_reply( TRANSACTION_ID, flags, mtrftr->max_meter,
      mtrftr->band_types, mtrftr->capabilities, mtrftr->max_bands, mtrftr->max_color );
    append_front_buffer( buffer, sizeof( openflow_service_header_t ) );
    memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) );
    multipart_reply = ( struct ofp_multipart_reply * ) ( ( char * ) buffer->data + sizeof( openflow_service_header_t ) );
    body_len = ( uint32_t ) ( ntohs( multipart_reply->header.length ) -
                              offsetof( struct ofp_multipart_reply, body ) );

    expect_memory( mock_multipart_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
    expect_value( mock_multipart_reply_handler, transaction_id, TRANSACTION_ID );
    expect_value( mock_multipart_reply_handler, type32, OFPMP_METER_FEATURES );
    expect_value( mock_multipart_reply_handler, flags32, ( uint32_t ) flags );
    expect_value( mock_multipart_reply_handler, data->length, body_len );
    expect_memory( mock_multipart_reply_handler, data->data, expected_data, stats_len );
    expect_memory( mock_multipart_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

    set_multipart_reply_handler( mock_multipart_reply_handler, USER_DATA );
    handle_openflow_message( buffer->data, buffer->length );

    stat = lookup_hash_entry( stats, "openflow_application_interface.multipart_reply_receive_succeeded" );
    assert_int_equal( ( int ) stat->value, 1 );

    xfree( expected_data );
    free_buffer( buffer );
    xfree( delete_hash_entry( stats, "openflow_application_interface.multipart_reply_receive_succeeded" ) );
  }
  {
    void *expected_data;
    uint16_t flags = OFPMPF_REPLY_MORE;
    uint16_t stats_len;
    uint32_t body_len;
    buffer *buffer;
    list_element *table_ftr_stats;
    struct ofp_multipart_reply *multipart_reply;
    struct ofp_table_features *tbf_stats[ 2 ];
    char name[OFP_MAX_TABLE_NAME_LEN] = "TableName";

    stats_len = sizeof( struct ofp_table_features );

    tbf_stats[ 0 ] = xcalloc( 1, stats_len );
    tbf_stats[ 1 ] = xcalloc( 1, stats_len );

    tbf_stats[ 0 ]->length = ( uint16_t ) sizeof( struct ofp_table_features );
    tbf_stats[ 0 ]->table_id = 1;
    memset( tbf_stats[ 0 ]->pad, 0, sizeof( tbf_stats[ 0 ]->pad ) );
    memcpy( tbf_stats[ 0 ]->name, name, sizeof( name ) );
    tbf_stats[ 0 ]->metadata_match = 0x1111222233334444;
    tbf_stats[ 0 ]->metadata_write = 0x5555666677778888;
    tbf_stats[ 0 ]->config = 0x12345678;
    tbf_stats[ 0 ]->max_entries = 0xAABBCCDD;

    memcpy( tbf_stats[ 1 ], tbf_stats[ 0 ], stats_len );
    tbf_stats[ 1 ]->table_id = 2;

    create_list( &table_ftr_stats );
    append_to_tail( &table_ftr_stats, tbf_stats[ 0 ] );
    append_to_tail( &table_ftr_stats, tbf_stats[ 1 ] );

    expected_data = xcalloc( 1, ( size_t ) ( stats_len * 2 ) );
    memcpy( expected_data, tbf_stats[ 0 ], stats_len );
    memcpy( ( char * ) expected_data + stats_len, tbf_stats[ 1 ], stats_len );

    buffer = create_table_features_multipart_reply( TRANSACTION_ID, flags, table_ftr_stats );
    append_front_buffer( buffer, sizeof( openflow_service_header_t ) );
    memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) );
    multipart_reply = ( struct ofp_multipart_reply * ) ( ( char * ) buffer->data + sizeof( openflow_service_header_t ) );
    body_len = ( uint32_t ) ( ntohs( multipart_reply->header.length ) -
                              offsetof( struct ofp_multipart_reply, body ) );

    expect_memory( mock_multipart_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
    expect_value( mock_multipart_reply_handler, transaction_id, TRANSACTION_ID );
    expect_value( mock_multipart_reply_handler, type32, OFPMP_TABLE_FEATURES );
    expect_value( mock_multipart_reply_handler, flags32, ( uint32_t ) flags );
    expect_value( mock_multipart_reply_handler, data->length, body_len );
    expect_memory( mock_multipart_reply_handler, data->data, expected_data, stats_len );
    expect_memory( mock_multipart_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

    set_multipart_reply_handler( mock_multipart_reply_handler, USER_DATA );
    handle_openflow_message( buffer->data, buffer->length );

    stat = lookup_hash_entry( stats, "openflow_application_interface.multipart_reply_receive_succeeded" );
    assert_int_equal( ( int ) stat->value, 1 );

    xfree( tbf_stats[ 0 ] );
    xfree( tbf_stats[ 1 ] );
    delete_list( table_ftr_stats );
    xfree( expected_data );
    free_buffer( buffer );
    xfree( delete_hash_entry( stats, "openflow_application_interface.multipart_reply_receive_succeeded" ) );
  }
  {
    void *expected_data;
    uint16_t flags = OFPMPF_REPLY_MORE;
    uint16_t stats_len;
    uint32_t body_len;
    buffer *buffer;
    list_element *port_desc_stats;
    struct ofp_multipart_reply *multipart_reply;
    struct ofp_port *port_stats[ 2 ];
    char name[OFP_MAX_PORT_NAME_LEN] = "PortName";

    stats_len = sizeof( struct ofp_port );

    port_stats[ 0 ] = xcalloc( 1, stats_len );
    port_stats[ 1 ] = xcalloc( 1, stats_len );

    port_stats[ 0 ]->port_no = 1;
    memset( port_stats[ 0 ]->pad, 0, sizeof( port_stats[ 0 ]->pad ) );
    memcpy( port_stats[ 0 ]->hw_addr, MAC_ADDR_X, sizeof( OFP_ETH_ALEN ) );
    memset( port_stats[ 0 ]->pad2, 0, sizeof( port_stats[ 0 ]->pad2 ) );
    memcpy( port_stats[ 0 ]->name, name, sizeof( name ) );
    port_stats[ 0 ]->config = OFPPC_PORT_DOWN;
    port_stats[ 0 ]->state = OFPPS_BLOCKED;
    port_stats[ 0 ]->curr = PORT_FEATURES;
    port_stats[ 0 ]->advertised = PORT_FEATURES;
    port_stats[ 0 ]->supported = PORT_FEATURES;
    port_stats[ 0 ]->peer = PORT_FEATURES;
    port_stats[ 0 ]->curr_speed = 0x11223344;
    port_stats[ 0 ]->max_speed = 0xAABBCCDD;

    memcpy( port_stats[ 1 ], port_stats[ 0 ], stats_len );
    port_stats[ 1 ]->port_no = 2;

    create_list( &port_desc_stats );
    append_to_tail( &port_desc_stats, port_stats[ 0 ] );
    append_to_tail( &port_desc_stats, port_stats[ 1 ] );

    expected_data = xcalloc( 1, ( size_t ) ( stats_len * 2 ) );
    memcpy( expected_data, port_stats[ 0 ], stats_len );
    memcpy( ( char * ) expected_data + stats_len, port_stats[ 1 ], stats_len );

    buffer = create_port_desc_multipart_reply( TRANSACTION_ID, flags, port_desc_stats );
    append_front_buffer( buffer, sizeof( openflow_service_header_t ) );
    memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) );

    multipart_reply = ( struct ofp_multipart_reply * ) ( ( char * ) buffer->data + sizeof( openflow_service_header_t ) );
    body_len = ( uint32_t ) ( ntohs( multipart_reply->header.length ) -
                              offsetof( struct ofp_multipart_reply, body ) );

    expect_memory( mock_multipart_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
    expect_value( mock_multipart_reply_handler, transaction_id, TRANSACTION_ID );
    expect_value( mock_multipart_reply_handler, type32, OFPMP_PORT_DESC );
    expect_value( mock_multipart_reply_handler, flags32, ( uint32_t ) flags );
    expect_value( mock_multipart_reply_handler, data->length, body_len );
    expect_memory( mock_multipart_reply_handler, data->data, expected_data, stats_len );
    expect_memory( mock_multipart_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

    set_multipart_reply_handler( mock_multipart_reply_handler, USER_DATA );
    handle_openflow_message( buffer->data, buffer->length );

    stat = lookup_hash_entry( stats, "openflow_application_interface.multipart_reply_receive_succeeded" );
    assert_int_equal( ( int ) stat->value, 1 );

    xfree( port_stats[ 0 ] );
    xfree( port_stats[ 1 ] );
    delete_list( port_desc_stats );
    xfree( expected_data );
    free_buffer( buffer );
    xfree( delete_hash_entry( stats, "openflow_application_interface.multipart_reply_receive_succeeded" ) );
  }
  {
    void *expected_data;
    uint16_t flags = 0;
    uint16_t stats_len;
    uint32_t body_len;
    uint32_t experimenter = VENDOR_ID;
    uint32_t exp_type = 1;
    buffer *body, *experimenter_multipart_reply;
    struct ofp_multipart_reply *multipart_reply;
    struct ofp_experimenter_multipart_header *exp_stats;

    body = alloc_buffer_with_length( 128 );
    append_back_buffer( body, 128 );
    memset( body->data, 0xa1, body->length );
    experimenter_multipart_reply = create_experimenter_multipart_reply( TRANSACTION_ID, flags, experimenter, exp_type, body );
    append_front_buffer( experimenter_multipart_reply, sizeof( openflow_service_header_t ) );
    memcpy( experimenter_multipart_reply->data, &messenger_header, sizeof( openflow_service_header_t ) );

    stats_len = ( uint16_t ) ( sizeof( struct ofp_experimenter_multipart_header ) + body->length );

    expected_data = xcalloc( 1, ( size_t ) stats_len );
    exp_stats = ( struct ofp_experimenter_multipart_header * ) expected_data;
    exp_stats->experimenter = experimenter;
    exp_stats->exp_type = exp_type;
    memcpy( exp_stats + 1, body->data, body->length );

    multipart_reply = ( struct ofp_multipart_reply * ) ( ( char * ) experimenter_multipart_reply->data + sizeof( openflow_service_header_t ) );
    body_len = ( uint32_t ) ( ntohs( multipart_reply->header.length ) -
                              offsetof( struct ofp_multipart_reply, body ) );

    expect_memory( mock_multipart_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
    expect_value( mock_multipart_reply_handler, transaction_id, TRANSACTION_ID );
    expect_value( mock_multipart_reply_handler, type32, OFPMP_EXPERIMENTER );
    expect_value( mock_multipart_reply_handler, flags32, ( uint32_t ) flags );
    expect_value( mock_multipart_reply_handler, data->length, body_len );
    expect_memory( mock_multipart_reply_handler, data->data, expected_data, body_len );
    expect_memory( mock_multipart_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

    set_multipart_reply_handler( mock_multipart_reply_handler, USER_DATA );
    handle_openflow_message( experimenter_multipart_reply->data, experimenter_multipart_reply->length );

    stat = lookup_hash_entry( stats, "openflow_application_interface.multipart_reply_receive_succeeded" );
    assert_int_equal( ( int ) stat->value, 1 );


    xfree( expected_data );
    free_buffer( body );
    free_buffer( experimenter_multipart_reply );
    xfree( delete_hash_entry( stats, "openflow_application_interface.multipart_reply_receive_succeeded" ) );
  }

  // barrier_reply
  {
    buffer *buffer;

    buffer = create_barrier_reply( TRANSACTION_ID );
    append_front_buffer( buffer, sizeof( openflow_service_header_t ) );
    memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) );

    expect_memory( mock_barrier_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
    expect_value( mock_barrier_reply_handler, transaction_id, TRANSACTION_ID );
    expect_memory( mock_barrier_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

    set_barrier_reply_handler( mock_barrier_reply_handler, USER_DATA );
    handle_openflow_message( buffer->data, buffer->length );

    stat = lookup_hash_entry( stats, "openflow_application_interface.barrier_reply_receive_succeeded" );
    assert_int_equal( ( int ) stat->value, 1 );

    free_buffer( buffer );
    xfree( delete_hash_entry( stats, "openflow_application_interface.barrier_reply_receive_succeeded" ) );
  }

  // queue_get_config_reply
  {
    size_t queue_len;
    uint32_t port = 1;
    list_element *list;
    buffer *expected_message;
    struct ofp_packet_queue *queue[ 2 ];
    struct ofp_queue_prop_min_rate *prop_header;

    queue_len = offsetof( struct ofp_packet_queue, properties ) + sizeof( struct ofp_queue_prop_min_rate );
    queue[ 0 ] = xcalloc( 1, queue_len );
    queue[ 1 ] = xcalloc( 1, queue_len );

    queue[ 0 ]->queue_id = 1;
    queue[ 0 ]->port = 2;
    queue[ 0 ]->len = ( uint16_t ) queue_len;
    prop_header = ( struct ofp_queue_prop_min_rate * ) queue[ 0 ]->properties;
    prop_header->prop_header.property = OFPQT_MIN_RATE;
    prop_header->prop_header.len = sizeof( struct ofp_queue_prop_min_rate );
    prop_header->rate = 1234;

    queue[ 1 ]->queue_id = 2;
    queue[ 1 ]->port = 3;
    queue[ 1 ]->len = ( uint16_t ) queue_len;
    prop_header = ( struct ofp_queue_prop_min_rate * ) queue[ 1 ]->properties;
    prop_header->prop_header.property = OFPQT_MIN_RATE;
    prop_header->prop_header.len = sizeof( struct ofp_queue_prop_min_rate );
    prop_header->rate = 5678;

    create_list( &list );
    append_to_tail( &list, queue[ 0 ] );
    append_to_tail( &list, queue[ 1 ] );

    expected_message = create_queue_get_config_reply( TRANSACTION_ID, port, list );
    append_front_buffer( expected_message, sizeof( openflow_service_header_t ) );
    memcpy( expected_message->data, &messenger_header, sizeof( openflow_service_header_t ) );

    expect_memory( mock_queue_get_config_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
    expect_value( mock_queue_get_config_reply_handler, transaction_id, TRANSACTION_ID );
    expect_value( mock_queue_get_config_reply_handler, port, port );
    expect_memory( mock_queue_get_config_reply_handler, queue1, queue[ 0 ], queue_len );
    expect_memory( mock_queue_get_config_reply_handler, queue2, queue[ 1 ], queue_len );
    expect_memory( mock_queue_get_config_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

    set_queue_get_config_reply_handler( mock_queue_get_config_reply_handler, USER_DATA );
    handle_openflow_message( expected_message->data, expected_message->length );

    stat = lookup_hash_entry( stats, "openflow_application_interface.queue_get_config_reply_receive_succeeded" );
    assert_int_equal( ( int ) stat->value, 1 );

    xfree( queue[ 0 ] );
    xfree( queue[ 1 ] );
    delete_list( list );
    free_buffer( expected_message );
    xfree( delete_hash_entry( stats, "openflow_application_interface.queue_get_config_reply_receive_succeeded" ) );
  }

  // role_reply
  {
    uint32_t role = OFPCR_ROLE_NOCHANGE;
    uint64_t generation_id = 0xAAAABBBBCCCCDDDD;
    buffer *buffer;

    buffer = create_role_reply( TRANSACTION_ID, role, generation_id );
    append_front_buffer( buffer, sizeof( openflow_service_header_t ) );
    memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) );
    expect_memory( mock_role_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
    expect_value( mock_role_reply_handler, transaction_id, TRANSACTION_ID );
    expect_value( mock_role_reply_handler, role, role );
    expect_memory( mock_role_reply_handler, &generation_id, &generation_id, sizeof( uint64_t ) );
    expect_memory( mock_role_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

    set_role_reply_handler( mock_role_reply_handler, USER_DATA );
    handle_openflow_message( buffer->data, buffer->length );

    stat = lookup_hash_entry( stats, "openflow_application_interface.role_reply_receive_succeeded" );
    assert_int_equal( ( int ) stat->value, 1 );

    free_buffer( buffer );
    xfree( delete_hash_entry( stats, "openflow_application_interface.role_reply_receive_succeeded" ) );
  }

  // get_async_reply
  {
    const uint32_t packet_in_mask[2] = { OFPR_ACTION, OFPR_INVALID_TTL };
    const uint32_t port_status_mask[2] = { OFPPR_DELETE, OFPPR_MODIFY };
    const uint32_t flow_removed_mask[2] = { OFPRR_DELETE, OFPRR_GROUP_DELETE };

    buffer *buffer = create_get_async_reply( TRANSACTION_ID, packet_in_mask, port_status_mask, flow_removed_mask );
    append_front_buffer( buffer, sizeof( openflow_service_header_t ) );
    memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) );
    expect_memory( mock_get_async_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
    expect_value( mock_get_async_reply_handler, transaction_id, TRANSACTION_ID );
    expect_memory( mock_get_async_reply_handler, packet_in_mask, packet_in_mask, (sizeof( uint32_t ) * 2) );
    expect_memory( mock_get_async_reply_handler, port_status_mask, port_status_mask, (sizeof( uint32_t ) * 2) );
    expect_memory( mock_get_async_reply_handler, flow_removed_mask, flow_removed_mask, (sizeof( uint32_t ) * 2) );
    expect_memory( mock_get_async_reply_handler, user_data, USER_DATA, USER_DATA_LEN );

    set_get_async_reply_handler( mock_get_async_reply_handler, USER_DATA );
    handle_openflow_message( buffer->data, buffer->length );

    stat = lookup_hash_entry( stats, "openflow_application_interface.get_async_reply_receive_succeeded" );
    assert_int_equal( ( int ) stat->value, 1 );

    free_buffer( buffer );
    xfree( delete_hash_entry( stats, "openflow_application_interface.get_async_reply_receive_succeeded" ) );
  }

  // unhandled message
  {
    buffer *buffer;

    buffer = create_hello( TRANSACTION_ID, NULL );
    struct ofp_header *header = buffer->data;
    header->type = OFPT_QUEUE_GET_CONFIG_REPLY + 1;
    append_front_buffer( buffer, sizeof( openflow_service_header_t ) );
    memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) );

    // FIXME
    handle_openflow_message( buffer->data, buffer->length );

    free_buffer( buffer );
  }
}


static void
test_handle_openflow_message_with_malformed_message() {
  buffer *buffer;
  openflow_service_header_t messenger_header;
  struct ofp_header *header;

  messenger_header.datapath_id = htonll( DATAPATH_ID );
  messenger_header.service_name_length = 0;

  buffer = create_hello( TRANSACTION_ID, NULL );
  header = buffer->data;
  header->length = htons( UINT16_MAX );
  append_front_buffer( buffer, sizeof( openflow_service_header_t ) );
  memcpy( buffer->data, &messenger_header, sizeof( openflow_service_header_t ) );

  handle_openflow_message( buffer->data, buffer->length );
    
  free_buffer( buffer );
}


static void
test_handle_openflow_message_if_message_is_NULL() {
  expect_assert_failure( handle_openflow_message( NULL, 1 ) );
}


static void
test_handle_openflow_message_if_message_length_is_zero() {
  buffer *data;

  data = alloc_buffer_with_length( 32 );

  expect_assert_failure( handle_openflow_message( data, 0 ) );

  free_buffer( data );
}


static void
test_handle_openflow_message_if_unhandled_message_type() {
  buffer *data;

  data = alloc_buffer_with_length( 32 );
  append_back_buffer( data, 32 );

  // FIXME
  handle_openflow_message( data, data->length );

  free_buffer( data );
}


/********************************************************************************
 * handle_message() tests.
 ********************************************************************************/

static void
test_handle_message_if_type_is_MESSENGER_OPENFLOW_MESSAGE() {
  buffer *data;
  openflow_service_header_t *header;

  data = create_barrier_reply( TRANSACTION_ID );

  assert_true( data != NULL );

  append_front_buffer( data, sizeof( openflow_service_header_t ) );

  header = data->data;
  header->datapath_id = htonll( DATAPATH_ID );
  header->service_name_length = 0;

  expect_memory( mock_barrier_reply_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_value( mock_barrier_reply_handler, transaction_id, TRANSACTION_ID );
  expect_value( mock_barrier_reply_handler, user_data, BARRIER_REPLY_USER_DATA );

  set_barrier_reply_handler( mock_barrier_reply_handler, BARRIER_REPLY_USER_DATA );
  handle_message( MESSENGER_OPENFLOW_MESSAGE, data->data, data->length );

  stat_entry *stat = lookup_hash_entry( stats, "openflow_application_interface.barrier_reply_receive_succeeded" );
  assert_int_equal( ( int ) stat->value, 1 );


  free_buffer( data );
  xfree( delete_hash_entry( stats, "openflow_application_interface.barrier_reply_receive_succeeded" ) );
}


static void
test_handle_message_if_type_is_MESSENGER_OPENFLOW_CONNECTED() {
  buffer *data = alloc_buffer_with_length( sizeof( openflow_service_header_t ) );
  append_back_buffer( data, sizeof( openflow_service_header_t ) );

  handle_message( MESSENGER_OPENFLOW_CONNECTED, data->data, data->length );

  stat_entry *stat = lookup_hash_entry( stats, "openflow_application_interface.switch_connected_receive_succeeded" );
  assert_int_equal( ( int ) stat->value, 1 );

  free_buffer( data );
  xfree( delete_hash_entry( stats, "openflow_application_interface.switch_connected_receive_succeeded" ) );
}


static void
test_handle_message_if_type_is_MESSENGER_OPENFLOW_DISCONNECTED() {
  uint64_t *datapath_id;
  buffer *data;

  data = alloc_buffer_with_length( sizeof( openflow_service_header_t ) );
  datapath_id = append_back_buffer( data, sizeof( openflow_service_header_t ) );

  *datapath_id = htonll( DATAPATH_ID );

  expect_memory( mock_switch_disconnected_handler, &datapath_id, &DATAPATH_ID, sizeof( uint64_t ) );
  expect_value( mock_switch_disconnected_handler, user_data, SWITCH_DISCONNECTED_USER_DATA );

  expect_string( mock_clear_send_queue, service_name, REMOTE_SERVICE_NAME );
  will_return( mock_clear_send_queue, true );

  set_switch_disconnected_handler( mock_switch_disconnected_handler, SWITCH_DISCONNECTED_USER_DATA );
  handle_message( MESSENGER_OPENFLOW_DISCONNECTED, data->data, data->length );

  stat_entry *stat = lookup_hash_entry( stats, "openflow_application_interface.switch_disconnected_receive_succeeded" );
  assert_int_equal( ( int ) stat->value, 1 );

  free_buffer( data );
  xfree( delete_hash_entry( stats, "openflow_application_interface.switch_disconnected_receive_succeeded" ) );
}


static void
test_handle_message_if_message_is_NULL() {
  expect_assert_failure( handle_message( MESSENGER_OPENFLOW_MESSAGE, NULL, 1 ) );
}


static void
test_handle_message_if_message_length_is_zero() {
  buffer *data;

  data = alloc_buffer_with_length( sizeof( openflow_service_header_t ) );

  expect_assert_failure( handle_message( MESSENGER_OPENFLOW_MESSAGE, data->data, 0 ) );

  free_buffer( data );
}


static void
test_handle_message_if_unhandled_message_type() {
  buffer *data;

  data = alloc_buffer_with_length( sizeof( openflow_service_header_t ) );
  append_back_buffer( data, sizeof( openflow_service_header_t ) );

  // FIXME
  handle_message( MESSENGER_OPENFLOW_DISCONNECTED + 1, data->data, data->length );

  stat_entry *stat = lookup_hash_entry( stats, "openflow_application_interface.undefined_switch_event_receive_succeeded" );
  assert_int_equal( ( int ) stat->value, 1 );

  free_buffer( data );
  xfree( delete_hash_entry( stats, "openflow_application_interface.undefined_switch_event_receive_succeeded" ) );
}


/********************************************************************************
 * delete_openflow_messages() tests.
 ********************************************************************************/

static void
test_delete_openflow_messages() {
  expect_string( mock_clear_send_queue, service_name, REMOTE_SERVICE_NAME );
  will_return( mock_clear_send_queue, true );

  assert_true( delete_openflow_messages( DATAPATH_ID ) );
}


static void
test_delete_openflow_messages_if_clear_send_queue_fails() {
  expect_string( mock_clear_send_queue, service_name, REMOTE_SERVICE_NAME );
  will_return( mock_clear_send_queue, false );

  assert_false( delete_openflow_messages( DATAPATH_ID ) );
}


/********************************************************************************
 * Run tests.
 ********************************************************************************/

int
main() {
  const UnitTest tests[] = {
    // initialization and finalization tests.
    unit_test_setup_teardown( test_init_openflow_application_interface_with_valid_custom_service_name, cleanup, cleanup ),
    unit_test_setup_teardown( test_init_openflow_application_interface_with_too_long_custom_service_name, cleanup, cleanup ),
    unit_test_setup_teardown( test_init_openflow_application_interface_if_already_initialized, init, cleanup ),

    unit_test_setup_teardown( test_finalize_openflow_application_interface, init, cleanup ),
    unit_test_setup_teardown( test_finalize_openflow_application_interface_if_not_initialized, cleanup, cleanup ),

    unit_test_setup_teardown( test_set_openflow_event_handlers, init, cleanup ),

    // switch ready handler tests.
    unit_test_setup_teardown( test_set_switch_ready_handler, init, cleanup ),
    unit_test_setup_teardown( test_set_simple_switch_ready_handler, init, cleanup ),
    unit_test_setup_teardown( test_set_switch_ready_handler_should_die_if_handler_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_handle_switch_ready, init, cleanup ),
    unit_test_setup_teardown( test_handle_switch_ready_with_simple_handler, init, cleanup ),

    // switch disconnected handler tests.
    unit_test_setup_teardown( test_set_switch_disconnected_handler, init, cleanup ),
    unit_test_setup_teardown( test_set_switch_disconnected_handler_if_handler_is_NULL, init, cleanup ),

    // error handler tests.
    unit_test_setup_teardown( test_set_error_handler, init, cleanup ),
    unit_test_setup_teardown( test_set_error_handler_if_handler_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_handle_error, init, cleanup ),
    unit_test_setup_teardown( test_handle_error_if_handler_is_not_registered, init, cleanup ),
    unit_test_setup_teardown( test_handle_error_if_message_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_handle_error_if_message_length_is_zero, init, cleanup ),

    // experimenter error handler tests.
    unit_test_setup_teardown( test_set_experimenter_error_handler, init, cleanup ),
    unit_test_setup_teardown( test_set_experimenter_error_handler_if_handler_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_handle_experimenter_error, init, cleanup ),
    unit_test_setup_teardown( test_handle_experimenter_error_if_handler_is_not_registered, init, cleanup ),
    unit_test_setup_teardown( test_handle_experimenter_error_if_message_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_handle_experimenter_error_if_message_length_is_zero, init, cleanup ),

    // echo_reply handler tests.
    unit_test_setup_teardown( test_set_echo_reply_handler, init, cleanup ),
    unit_test_setup_teardown( test_set_echo_reply_handler_if_handler_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_handle_echo_reply, init, cleanup ),
    unit_test_setup_teardown( test_handle_echo_reply_without_data, init, cleanup ),
    unit_test_setup_teardown( test_handle_echo_reply_if_handler_is_not_registered, init, cleanup ),
    unit_test_setup_teardown( test_handle_echo_reply_if_message_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_handle_echo_reply_if_message_length_is_zero, init, cleanup ),

    // experimenter handler tests.
    unit_test_setup_teardown( test_set_experimenter_handler, init, cleanup ),
    unit_test_setup_teardown( test_set_experimenter_handler_if_handler_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_handle_experimenter, init, cleanup ),
    unit_test_setup_teardown( test_handle_experimenter_without_data, init, cleanup ),
    unit_test_setup_teardown( test_handle_experimenter_if_handler_is_not_registered, init, cleanup ),
    unit_test_setup_teardown( test_handle_experimenter_if_message_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_handle_experimenter_if_message_length_is_zero, init, cleanup ),

    // features reply handler tests.
    unit_test_setup_teardown( test_set_features_reply_handler, init, cleanup ),
    unit_test_setup_teardown( test_set_features_reply_handler_if_handler_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_handle_features_reply, init, cleanup ),
    unit_test_setup_teardown( test_handle_features_reply_if_handler_is_not_registered, init, cleanup ),
    unit_test_setup_teardown( test_handle_features_reply_if_message_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_handle_features_reply_if_message_length_is_zero, init, cleanup ),

    // get config reply handler tests.
    unit_test_setup_teardown( test_set_get_config_reply_handler, init, cleanup ),
    unit_test_setup_teardown( test_set_get_config_reply_handler_if_handler_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_handle_get_config_reply, init, cleanup ),
    unit_test_setup_teardown( test_handle_get_config_reply_if_handler_is_not_registered, init, cleanup ),
    unit_test_setup_teardown( test_handle_get_config_reply_if_message_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_handle_get_config_reply_if_message_length_is_zero, init, cleanup ),

    // flow removed handler tests.
    unit_test_setup_teardown( test_set_flow_removed_handler, init, cleanup ),
    unit_test_setup_teardown( test_set_flow_removed_handler_if_handler_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_handle_flow_removed, init, cleanup ),
    unit_test_setup_teardown( test_handle_flow_removed_with_simple_handler, init, cleanup ),
    unit_test_setup_teardown( test_set_simple_flow_removed_handler, init, cleanup ),
    unit_test_setup_teardown( test_handle_flow_removed_if_handler_is_not_registered, init, cleanup ),
    unit_test_setup_teardown( test_handle_flow_removed_if_message_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_handle_flow_removed_if_message_length_is_zero, init, cleanup ),

    // port status handler tests.
    unit_test_setup_teardown( test_set_port_status_handler, init, cleanup ),
    unit_test_setup_teardown( test_set_port_status_handler_if_handler_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_handle_port_status, init, cleanup ),
    unit_test_setup_teardown( test_handle_port_status_if_handler_is_not_registered, init, cleanup ),
    unit_test_setup_teardown( test_handle_port_status_if_message_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_handle_port_status_if_message_length_is_zero, init, cleanup ),

    // multipart reply handler tests.
    unit_test_setup_teardown( test_set_multipart_reply_handler, init, cleanup ),
    unit_test_setup_teardown( test_set_multipart_reply_handler_if_handler_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_handle_multipart_reply_if_type_is_OFPMP_DESC, init, cleanup ),
    unit_test_setup_teardown( test_handle_multipart_reply_if_type_is_OFPMP_FLOW, init, cleanup ),
    unit_test_setup_teardown( test_handle_multipart_reply_if_type_is_OFPMP_AGGREGATE, init, cleanup ),
    unit_test_setup_teardown( test_handle_multipart_reply_if_type_is_OFPMP_TABLE, init, cleanup ),
    unit_test_setup_teardown( test_handle_multipart_reply_if_type_is_OFPMP_PORT_STATS, init, cleanup ),
    unit_test_setup_teardown( test_handle_multipart_reply_if_type_is_OFPMP_QUEUE, init, cleanup ),
    unit_test_setup_teardown( test_handle_multipart_reply_if_type_is_OFPMP_GROUP, init, cleanup ),
    unit_test_setup_teardown( test_handle_multipart_reply_if_type_is_OFPMP_GROUP_DESC, init, cleanup ),
    unit_test_setup_teardown( test_handle_multipart_reply_if_type_is_OFPMP_GROUP_FEATURES, init, cleanup ),
    unit_test_setup_teardown( test_handle_multipart_reply_if_type_is_OFPMP_METER, init, cleanup ),
    unit_test_setup_teardown( test_handle_multipart_reply_if_type_is_OFPMP_METER_CONFIG, init, cleanup ),
    unit_test_setup_teardown( test_handle_multipart_reply_if_type_is_OFPMP_METER_FEATURES, init, cleanup ),
    unit_test_setup_teardown( test_handle_multipart_reply_if_type_is_OFPMP_TABLE_FEATURES, init, cleanup ),
    unit_test_setup_teardown( test_handle_multipart_reply_if_type_is_OFPMP_PORT_DESC, init, cleanup ),
    unit_test_setup_teardown( test_handle_multipart_reply_if_type_is_OFPMP_EXPERIMENTER, init, cleanup ),
    unit_test_setup_teardown( test_handle_multipart_reply_with_undefined_type, init, cleanup ),
    unit_test_setup_teardown( test_handle_multipart_reply_if_handler_is_not_registered, init, cleanup ),
    unit_test_setup_teardown( test_handle_multipart_reply_if_message_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_handle_multipart_reply_if_message_length_is_zero, init, cleanup ),

    // barrier reply handler tests.
    unit_test_setup_teardown( test_set_barrier_reply_handler, init, cleanup ),
    unit_test_setup_teardown( test_set_barrier_reply_handler_if_handler_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_handle_barrier_reply, init, cleanup ),
    unit_test_setup_teardown( test_handle_barrier_reply_if_handler_is_not_registered, init, cleanup ),
    unit_test_setup_teardown( test_handle_barrier_reply_if_message_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_handle_barrier_reply_if_message_length_is_zero, init, cleanup ),

    // queue get config reply handler tests.
    unit_test_setup_teardown( test_set_queue_get_config_reply_handler, init, cleanup ),
    unit_test_setup_teardown( test_set_queue_get_config_reply_handler_if_handler_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_handle_queue_get_config_reply, init, cleanup ),
    unit_test_setup_teardown( test_handle_queue_get_config_reply_without_queues, init, cleanup ),
    unit_test_setup_teardown( test_handle_queue_get_config_reply_if_handler_is_not_registered, init, cleanup ),
    unit_test_setup_teardown( test_handle_queue_get_config_reply_if_message_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_handle_queue_get_config_reply_if_message_length_is_zero, init, cleanup ),

    // role reply handler tests.
    unit_test_setup_teardown( test_set_role_reply_handler, init, cleanup ),
    unit_test_setup_teardown( test_set_role_reply_handler_if_handler_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_handle_role_reply, init, cleanup ),
    unit_test_setup_teardown( test_handle_role_reply_if_handler_is_not_registered, init, cleanup ),
    unit_test_setup_teardown( test_handle_role_reply_if_message_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_handle_role_reply_if_message_length_is_zero, init, cleanup ),

    // get async reply handler tests.
    unit_test_setup_teardown( test_set_get_async_reply_handler, init, cleanup ),
    unit_test_setup_teardown( test_set_get_async_reply_handler_if_handler_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_handle_get_async_reply, init, cleanup ),
    unit_test_setup_teardown( test_handle_get_async_reply_if_handler_is_not_registered, init, cleanup ),
    unit_test_setup_teardown( test_handle_get_async_reply_if_message_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_handle_get_async_reply_if_message_length_is_zero, init, cleanup ),

    // list switches reply handler tests.
    unit_test_setup_teardown( test_set_list_switches_reply_handler, init, cleanup ),
    unit_test_setup_teardown( test_set_list_switches_reply_handler_if_handler_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_handle_list_switches_reply, init, cleanup ),
    unit_test_setup_teardown( test_handle_list_switches_reply_if_data_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_handle_list_switches_reply_if_length_is_zero, init, cleanup ),

    // packet-in handler tests.
    unit_test_setup_teardown( test_set_packet_in_handler, init, cleanup ),
    unit_test_setup_teardown( test_set_simple_packet_in_handler, init, cleanup ),
    unit_test_setup_teardown( test_set_packet_in_handler_should_die_if_handler_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_handle_packet_in, init, cleanup ),
    unit_test_setup_teardown( test_handle_packet_in_with_simple_handler, init, cleanup ),
    unit_test_setup_teardown( test_handle_packet_in_with_malformed_packet, init, cleanup ),
    unit_test_setup_teardown( test_handle_packet_in_without_data, init, cleanup ),
    unit_test_setup_teardown( test_handle_packet_in_without_handler, init, cleanup ),
    unit_test_setup_teardown( test_handle_packet_in_should_die_if_message_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_handle_packet_in_should_die_if_message_length_is_zero, init, cleanup ),

    // miscellaneous tests.
    unit_test_setup_teardown( test_insert_dpid, init, cleanup ),
    unit_test_setup_teardown( test_insert_dpid_if_head_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_insert_dpid_if_dpid_is_NULL, init, cleanup ),

    unit_test_setup_teardown( test_handle_switch_events_if_type_is_MESSENGER_OPENFLOW_CONNECTED, init, cleanup ),
    unit_test_setup_teardown( test_handle_switch_events_if_type_is_MESSENGER_OPENFLOW_DISCONNECTED, init, cleanup ),
    unit_test_setup_teardown( test_handle_switch_events_if_message_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_handle_switch_events_if_message_length_is_zero, init, cleanup ),
    unit_test_setup_teardown( test_handle_switch_events_if_message_length_is_too_big, init, cleanup ),
    unit_test_setup_teardown( test_handle_switch_events_if_unhandled_message_type, init, cleanup ),

    unit_test_setup_teardown( test_handle_openflow_message, init, cleanup ),
    unit_test_setup_teardown( test_handle_openflow_message_with_malformed_message, init, cleanup ),
    unit_test_setup_teardown( test_handle_openflow_message_if_message_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_handle_openflow_message_if_message_length_is_zero, init, cleanup ),
    unit_test_setup_teardown( test_handle_openflow_message_if_unhandled_message_type, init, cleanup ),

    unit_test_setup_teardown( test_handle_message_if_type_is_MESSENGER_OPENFLOW_MESSAGE, init, cleanup ),
    unit_test_setup_teardown( test_handle_message_if_type_is_MESSENGER_OPENFLOW_CONNECTED, init, cleanup ),
    unit_test_setup_teardown( test_handle_message_if_type_is_MESSENGER_OPENFLOW_DISCONNECTED, init, cleanup ),
    unit_test_setup_teardown( test_handle_message_if_message_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_handle_message_if_message_length_is_zero, init, cleanup ),
    unit_test_setup_teardown( test_handle_message_if_unhandled_message_type, init, cleanup ),

    // send_openflow_message() tests.
    unit_test_setup_teardown( test_send_openflow_message, init, cleanup ),
    unit_test_setup_teardown( test_send_openflow_message_if_message_is_NULL, init, cleanup ),
    unit_test_setup_teardown( test_send_openflow_message_if_message_length_is_zero, init, cleanup ),

    // delete_openflow_messages() tests.
    unit_test_setup_teardown( test_delete_openflow_messages, init, cleanup ),
    unit_test_setup_teardown( test_delete_openflow_messages_if_clear_send_queue_fails, init, cleanup ),
  };
  setup_leak_detector();
  return run_tests( tests );
}


/*
 * Local variables:
 * c-basic-offset: 2
 * indent-tabs-mode: nil
 * End:
 */