test_timers.cpp 7.38 KB
Newer Older
somdoron's avatar
somdoron committed
1
/*
2
    Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
somdoron's avatar
somdoron committed
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

    This file is part of libzmq, the ZeroMQ core engine in C++.

    libzmq is free software; you can redistribute it and/or modify it under
    the terms of the GNU Lesser General Public License (LGPL) as published
    by the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.

    As a special exception, the Contributors give you permission to link
    this library with independent modules to produce an executable,
    regardless of the license terms of these independent modules, and to
    copy and distribute the resulting executable under terms of your choice,
    provided that you also meet, for each linked independent module, the
    terms and conditions of the license of that module. An independent
    module is a module which is not derived from or based on this library.
    If you modify this library, you must extend this exception to your
    version of the library.

    libzmq 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 Lesser General Public
    License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

30
#define __STDC_LIMIT_MACROS // to define SIZE_MAX with older compilers
31
#include "testutil.hpp"
32 33 34 35 36 37 38 39 40
#include "testutil_unity.hpp"

void setUp ()
{
}

void tearDown ()
{
}
somdoron's avatar
somdoron committed
41

42
void handler (int timer_id_, void *arg_)
somdoron's avatar
somdoron committed
43
{
44 45
    (void) timer_id_; //  Stop 'unused' compiler warnings
    *((bool *) arg_) = true;
somdoron's avatar
somdoron committed
46 47
}

48
int sleep_and_execute (void *timers_)
49 50 51 52 53
{
    int timeout = zmq_timers_timeout (timers_);

    //  Sleep methods are inaccurate, so we sleep in a loop until time arrived
    while (timeout > 0) {
54
        msleep (timeout);
55
        timeout = zmq_timers_timeout (timers_);
56 57
    }

58
    return zmq_timers_execute (timers_);
59 60
}

61 62 63 64
void test_null_timer_pointers ()
{
    void *timers = NULL;

65
    TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_timers_destroy (&timers));
66 67 68

//  TODO this currently triggers an access violation
#if 0
69
  TEST_ASSERT_FAILURE_ERRNO(EFAULT, zmq_timers_destroy (NULL));
70 71 72 73 74
#endif

    const size_t dummy_interval = 100;
    const int dummy_timer_id = 1;

75 76 77 78
    TEST_ASSERT_FAILURE_ERRNO (
      EFAULT, zmq_timers_add (timers, dummy_interval, &handler, NULL));
    TEST_ASSERT_FAILURE_ERRNO (
      EFAULT, zmq_timers_add (&timers, dummy_interval, &handler, NULL));
79

80 81 82 83
    TEST_ASSERT_FAILURE_ERRNO (EFAULT,
                               zmq_timers_cancel (timers, dummy_timer_id));
    TEST_ASSERT_FAILURE_ERRNO (EFAULT,
                               zmq_timers_cancel (&timers, dummy_timer_id));
84

85 86 87 88 89
    TEST_ASSERT_FAILURE_ERRNO (
      EFAULT, zmq_timers_set_interval (timers, dummy_timer_id, dummy_interval));
    TEST_ASSERT_FAILURE_ERRNO (
      EFAULT,
      zmq_timers_set_interval (&timers, dummy_timer_id, dummy_interval));
90

91 92 93 94
    TEST_ASSERT_FAILURE_ERRNO (EFAULT,
                               zmq_timers_reset (timers, dummy_timer_id));
    TEST_ASSERT_FAILURE_ERRNO (EFAULT,
                               zmq_timers_reset (&timers, dummy_timer_id));
95

96 97
    TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_timers_timeout (timers));
    TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_timers_timeout (&timers));
98

99 100
    TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_timers_execute (timers));
    TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_timers_execute (&timers));
101 102
}

103 104 105
void test_corner_cases ()
{
    void *timers = zmq_timers_new ();
106
    TEST_ASSERT_NOT_NULL (timers);
107 108 109 110 111

    const size_t dummy_interval = SIZE_MAX;
    const int dummy_timer_id = 1;

    //  attempt to cancel non-existent timer
112 113
    TEST_ASSERT_FAILURE_ERRNO (EINVAL,
                               zmq_timers_cancel (timers, dummy_timer_id));
114 115

    //  attempt to set interval of non-existent timer
116 117
    TEST_ASSERT_FAILURE_ERRNO (
      EINVAL, zmq_timers_set_interval (timers, dummy_timer_id, dummy_interval));
118 119

    //  attempt to reset non-existent timer
120 121
    TEST_ASSERT_FAILURE_ERRNO (EINVAL,
                               zmq_timers_reset (timers, dummy_timer_id));
122 123

    //  attempt to add NULL handler
124 125
    TEST_ASSERT_FAILURE_ERRNO (
      EFAULT, zmq_timers_add (timers, dummy_interval, NULL, NULL));
126

127 128
    const int timer_id = TEST_ASSERT_SUCCESS_ERRNO (
      zmq_timers_add (timers, dummy_interval, handler, NULL));
129 130 131

    //  attempt to cancel timer twice
    //  TODO should this case really be an error? canceling twice could be allowed
132
    TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_cancel (timers, timer_id));
133

134
    TEST_ASSERT_FAILURE_ERRNO (EINVAL, zmq_timers_cancel (timers, timer_id));
135

136
    //  timeout without any timers active
137
    TEST_ASSERT_FAILURE_ERRNO (EINVAL, zmq_timers_timeout (timers));
138

139 140
    //  cleanup
    TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_destroy (&timers));
141 142
}

143
void test_timers ()
somdoron's avatar
somdoron committed
144
{
145
    void *timers = zmq_timers_new ();
146
    TEST_ASSERT_NOT_NULL (timers);
somdoron's avatar
somdoron committed
147 148 149

    bool timer_invoked = false;

150
    const unsigned long full_timeout = 100;
151 152
    void *const stopwatch = zmq_stopwatch_start ();

153 154
    const int timer_id = TEST_ASSERT_SUCCESS_ERRNO (
      zmq_timers_add (timers, full_timeout, handler, &timer_invoked));
somdoron's avatar
somdoron committed
155

156
    //  Timer should not have been invoked yet
157
    TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_execute (timers));
158 159

    if (zmq_stopwatch_intermediate (stopwatch) < full_timeout) {
160
        TEST_ASSERT_FALSE (timer_invoked);
161
    }
somdoron's avatar
somdoron committed
162 163

    //  Wait half the time and check again
164
    long timeout = TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_timeout (timers));
165
    msleep (timeout / 2);
166
    TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_execute (timers));
167
    if (zmq_stopwatch_intermediate (stopwatch) < full_timeout) {
168
        TEST_ASSERT_FALSE (timer_invoked);
169
    }
somdoron's avatar
somdoron committed
170

171
    // Wait until the end
172 173
    TEST_ASSERT_SUCCESS_ERRNO (sleep_and_execute (timers));
    TEST_ASSERT_TRUE (timer_invoked);
somdoron's avatar
somdoron committed
174 175 176
    timer_invoked = false;

    //  Wait half the time and check again
177
    timeout = TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_timeout (timers));
178
    msleep (timeout / 2);
179
    TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_execute (timers));
180
    if (zmq_stopwatch_intermediate (stopwatch) < 2 * full_timeout) {
181
        TEST_ASSERT_FALSE (timer_invoked);
182
    }
somdoron's avatar
somdoron committed
183 184

    // Reset timer and wait half of the time left
185
    TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_reset (timers, timer_id));
186
    msleep (timeout / 2);
187
    TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_execute (timers));
188
    if (zmq_stopwatch_stop (stopwatch) < 2 * full_timeout) {
189
        TEST_ASSERT_FALSE (timer_invoked);
190
    }
somdoron's avatar
somdoron committed
191 192

    // Wait until the end
193 194
    TEST_ASSERT_SUCCESS_ERRNO (sleep_and_execute (timers));
    TEST_ASSERT_TRUE (timer_invoked);
somdoron's avatar
somdoron committed
195 196 197
    timer_invoked = false;

    // reschedule
198 199 200
    TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_set_interval (timers, timer_id, 50));
    TEST_ASSERT_SUCCESS_ERRNO (sleep_and_execute (timers));
    TEST_ASSERT_TRUE (timer_invoked);
somdoron's avatar
somdoron committed
201 202 203
    timer_invoked = false;

    // cancel timer
204 205
    timeout = TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_timeout (timers));
    TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_cancel (timers, timer_id));
206
    msleep (timeout * 2);
207 208
    TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_execute (timers));
    TEST_ASSERT_FALSE (timer_invoked);
somdoron's avatar
somdoron committed
209

210 211
    TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_destroy (&timers));
}
somdoron's avatar
somdoron committed
212

213 214 215
int main ()
{
    setup_test_environment ();
216

217 218 219 220 221
    UNITY_BEGIN ();
    RUN_TEST (test_timers);
    RUN_TEST (test_null_timer_pointers);
    RUN_TEST (test_corner_cases);
    return UNITY_END ();
somdoron's avatar
somdoron committed
222
}