File size: 4,157 Bytes
78d2150 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
#include "../../unity/unity.h"
#include <errno.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
/*
Test strategy:
- Provide a mock fsync() in this translation unit to control return
values and errno across calls.
- Call the target static function ifsync(int fd) directly.
- Verify that ifsync retries on EINTR and returns appropriately on
success or on non-EINTR errors.
- Ensure only the target function behavior is tested.
*/
/* Mock machinery for fsync */
typedef struct {
int ret; /* return value for fsync */
int err; /* errno to set for fsync */
} mock_fsync_step_t;
static mock_fsync_step_t mock_fsync_steps[64];
static int mock_fsync_len = 0;
static int mock_fsync_pos = 0;
static int mock_fsync_calls = 0;
static void mock_fsync_reset(void)
{
mock_fsync_len = 0;
mock_fsync_pos = 0;
mock_fsync_calls = 0;
}
static void mock_fsync_set_steps(const mock_fsync_step_t *steps, int len)
{
if (len > (int)(sizeof(mock_fsync_steps) / sizeof(mock_fsync_steps[0])))
len = (int)(sizeof(mock_fsync_steps) / sizeof(mock_fsync_steps[0]));
for (int i = 0; i < len; i++)
mock_fsync_steps[i] = steps[i];
mock_fsync_len = len;
mock_fsync_pos = 0;
mock_fsync_calls = 0;
}
/*
Mocked fsync used by ifsync(). Since this test file is included
in the same translation unit after the dd source, this definition
will satisfy references to fsync within this TU for testing.
*/
int fsync(int fd)
{
(void)fd; /* Not used in mock */
mock_fsync_calls++;
if (mock_fsync_pos < mock_fsync_len) {
int r = mock_fsync_steps[mock_fsync_pos].ret;
errno = mock_fsync_steps[mock_fsync_pos].err;
mock_fsync_pos++;
return r;
}
/* Default fall-through if sequence exhausted: succeed */
errno = 0;
return 0;
}
void setUp(void)
{
mock_fsync_reset();
}
void tearDown(void)
{
/* nothing */
}
/* Tests */
/* Immediate success: ifsync should return 0 and call fsync once. */
void test_ifsync_immediate_success(void)
{
mock_fsync_step_t seq[] = {
{ 0, 0 }
};
mock_fsync_set_steps(seq, 1);
int rc = ifsync(123);
TEST_ASSERT_EQUAL_INT(0, rc);
TEST_ASSERT_EQUAL_INT(1, mock_fsync_calls);
}
/* One EINTR then success: ifsync should retry and return 0; two calls total. */
void test_ifsync_eintr_then_success(void)
{
mock_fsync_step_t seq[] = {
{ -1, EINTR },
{ 0, 0 }
};
mock_fsync_set_steps(seq, 2);
int rc = ifsync(5);
TEST_ASSERT_EQUAL_INT(0, rc);
TEST_ASSERT_EQUAL_INT(2, mock_fsync_calls);
}
/* Multiple EINTRs then success: ensure loop continues appropriately. */
void test_ifsync_multiple_eintr_then_success(void)
{
mock_fsync_step_t seq[] = {
{ -1, EINTR },
{ -1, EINTR },
{ -1, EINTR },
{ 0, 0 }
};
mock_fsync_set_steps(seq, 4);
int rc = ifsync(7);
TEST_ASSERT_EQUAL_INT(0, rc);
TEST_ASSERT_EQUAL_INT(4, mock_fsync_calls);
}
/* Immediate non-EINTR failure: ifsync should return -1 and not retry. */
void test_ifsync_immediate_non_eintr_failure(void)
{
mock_fsync_step_t seq[] = {
{ -1, EIO }
};
mock_fsync_set_steps(seq, 1);
errno = 0;
int rc = ifsync(9);
TEST_ASSERT_EQUAL_INT(-1, rc);
TEST_ASSERT_EQUAL_INT(EIO, errno);
TEST_ASSERT_EQUAL_INT(1, mock_fsync_calls);
}
/* EINTR followed by non-EINTR failure: should retry once then return -1. */
void test_ifsync_eintr_then_non_eintr_failure(void)
{
mock_fsync_step_t seq[] = {
{ -1, EINTR },
{ -1, EFAULT }
};
mock_fsync_set_steps(seq, 2);
errno = 0;
int rc = ifsync(11);
TEST_ASSERT_EQUAL_INT(-1, rc);
TEST_ASSERT_EQUAL_INT(EFAULT, errno);
TEST_ASSERT_EQUAL_INT(2, mock_fsync_calls);
}
int main(void)
{
UNITY_BEGIN();
RUN_TEST(test_ifsync_immediate_success);
RUN_TEST(test_ifsync_eintr_then_success);
RUN_TEST(test_ifsync_multiple_eintr_then_success);
RUN_TEST(test_ifsync_immediate_non_eintr_failure);
RUN_TEST(test_ifsync_eintr_then_non_eintr_failure);
return UNITY_END();
} |