blob: 1ff23a85a05a9f25132a7b56d9ca9dc11fc227bc [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <CUnit/CUnit.h>
#include <guacamole/flag.h>
#include <pthread.h>
#include <stdint.h>
/**
* The maximum number of milliseconds to wait for a test event to be flagged.
*/
#define TEST_TIMEOUT 250
/**
* Arbitrary test event #1.
*/
#define TEST_EVENT_A 1
/**
* Arbitrary test event #2.
*/
#define TEST_EVENT_B 2
/**
* Arbitrary test event #3.
*/
#define TEST_EVENT_C 16
/**
* Arbitrary test event #4.
*/
#define TEST_EVENT_D 64
/**
* Thread that waits up to TEST_TIMEOUT milliseconds for TEST_EVENT_B or
* TEST_EVENT_C to be flagged on a given guac_flag, returning the
* result of that wait.
*
* @param data
* The guac_flag to wait on.
*
* @return
* An intptr_t (NOT a pointer) containing the value returned by
* guac_flag_timedwait_and_lock().
*/
static void* flag_wait_thread(void* data) {
guac_flag* flag = (guac_flag*) data;
int retval = guac_flag_timedwait_and_lock(flag, TEST_EVENT_B | TEST_EVENT_C, TEST_TIMEOUT);
guac_flag_unlock(flag);
return (void*) ((intptr_t) retval);
}
/**
* Waits up to TEST_TIMEOUT milliseconds for TEST_EVENT_B or TEST_EVENT_C to be
* flagged on the given guac_flag, returning the result of that
* wait. If provided, optional sets of flags will be additionally set or
* cleared after the wait for the flag has started.
*
* @param flag
* The guac_flag to wait on.
*
* @param set_flags
* The flags that should be set, if any.
*
* @param clear_flags
* The flags that should be cleared, if any.
*
* @return
* The value returned by guac_flag_timedwait_and_lock() after
* waiting for TEST_EVENT_B or TEST_EVENT_C to be flagged.
*/
static int wait_for_flag(guac_flag* flag, int set_flags, int clear_flags) {
/* Spawn thread that can independently wait for events to be flagged */
pthread_t test_thread;
CU_ASSERT_FALSE_FATAL(pthread_create(&test_thread, NULL, flag_wait_thread, flag));
/* Set/clear any requested event flags */
if (set_flags) guac_flag_set(flag, set_flags);
if (clear_flags) guac_flag_clear(flag, clear_flags);
/* Wait for thread to finish waiting for events */
void* retval;
CU_ASSERT_FALSE(pthread_join(test_thread, &retval));
return (int) ((intptr_t) retval);
}
/**
* Verifies that a thread waiting on a particular event will NOT be notified if
* absolutely zero events ever occur.
*/
void test_flag__ignore_total_silence(void) {
guac_flag test_flag;
guac_flag_init(&test_flag);
/* Verify no interesting events occur if we set zero flags */
CU_ASSERT_FALSE(wait_for_flag(&test_flag, 0, 0));
guac_flag_destroy(&test_flag);
}
/**
* Verifies that a thread waiting on a particular event will NOT be notified if
* that event never occurs, even if other events are occurring.
*/
void test_flag__ignore_uninteresting_events(void) {
guac_flag test_flag;
guac_flag_init(&test_flag);
/* Verify no interesting events occurred if we only fire uninteresting
* events */
CU_ASSERT_FALSE(wait_for_flag(&test_flag, TEST_EVENT_A, 0));
CU_ASSERT_FALSE(wait_for_flag(&test_flag, TEST_EVENT_D, TEST_EVENT_C));
CU_ASSERT_FALSE(wait_for_flag(&test_flag, TEST_EVENT_A | TEST_EVENT_D, 0));
guac_flag_destroy(&test_flag);
}
/**
* Verifies that a thread waiting on a particular event will be notified when
* that event occurs.
*/
void test_flag__wake_for_interesting_events(void) {
guac_flag test_flag;
guac_flag_init(&test_flag);
/* Verify interesting events are reported if fired ... */
CU_ASSERT_TRUE(wait_for_flag(&test_flag, TEST_EVENT_B | TEST_EVENT_C, 0));
/* ... and continue to be reported if they remain set ... */
guac_flag_clear(&test_flag, TEST_EVENT_B);
CU_ASSERT_TRUE(wait_for_flag(&test_flag, 0, 0));
/* ... but not if all interesting events have since been cleared */
guac_flag_clear(&test_flag, TEST_EVENT_C);
CU_ASSERT_FALSE(wait_for_flag(&test_flag, 0, 0));
guac_flag_destroy(&test_flag);
}