tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_logging.cpp (5203B)


      1 /*
      2 * Copyright © 2016 Mozilla Foundation
      3 *
      4 * This program is made available under an ISC-style license.  See the
      5 * accompanying file LICENSE for details.
      6 */
      7 
      8 /* cubeb_logging test  */
      9 #include "gtest/gtest.h"
     10 #if !defined(_XOPEN_SOURCE)
     11 #define _XOPEN_SOURCE 600
     12 #endif
     13 #include "cubeb/cubeb.h"
     14 #include "cubeb_log.h"
     15 #include <atomic>
     16 #include <math.h>
     17 #include <memory>
     18 #include <stdio.h>
     19 #include <stdlib.h>
     20 #include <thread>
     21 
     22 #include "common.h"
     23 
     24 #define PRINT_LOGS_TO_STDERR 0
     25 
     26 std::atomic<uint32_t> log_statements_received = {0};
     27 std::atomic<uint32_t> data_callback_call_count = {0};
     28 
     29 static void
     30 test_logging_callback(char const * fmt, ...)
     31 {
     32  log_statements_received++;
     33 #if PRINT_LOGS_TO_STDERR == 1
     34  char buf[1024];
     35  va_list argslist;
     36  va_start(argslist, fmt);
     37  vsnprintf(buf, 1024, fmt, argslist);
     38  fprintf(stderr, "%s\n", buf);
     39  va_end(argslist);
     40 #endif // PRINT_LOGS_TO_STDERR
     41 }
     42 
     43 static long
     44 data_cb_load(cubeb_stream * stream, void * user, const void * inputbuffer,
     45             void * outputbuffer, long nframes)
     46 {
     47  data_callback_call_count++;
     48  return nframes;
     49 }
     50 
     51 static void
     52 state_cb(cubeb_stream * stream, void * /*user*/, cubeb_state state)
     53 {
     54  if (stream == NULL)
     55    return;
     56 
     57  switch (state) {
     58  case CUBEB_STATE_STARTED:
     59    fprintf(stderr, "stream started\n");
     60    break;
     61  case CUBEB_STATE_STOPPED:
     62    fprintf(stderr, "stream stopped\n");
     63    break;
     64  case CUBEB_STATE_DRAINED:
     65    fprintf(stderr, "stream drained\n");
     66    break;
     67  default:
     68    fprintf(stderr, "unknown stream state %d\n", state);
     69  }
     70 
     71  return;
     72 }
     73 
     74 // Waits for at least one audio callback to have occured.
     75 void
     76 wait_for_audio_callback()
     77 {
     78  uint32_t audio_callback_index =
     79      data_callback_call_count.load(std::memory_order_acquire);
     80  while (audio_callback_index ==
     81         data_callback_call_count.load(std::memory_order_acquire)) {
     82    delay(100);
     83  }
     84 }
     85 
     86 TEST(cubeb, logging)
     87 {
     88  cubeb * ctx;
     89  cubeb_stream * stream;
     90  cubeb_stream_params output_params;
     91  int r;
     92  uint32_t latency_frames = 0;
     93 
     94  cubeb_set_log_callback(CUBEB_LOG_NORMAL, test_logging_callback);
     95 
     96  r = common_init(&ctx, "Cubeb logging test");
     97  ASSERT_EQ(r, CUBEB_OK) << "Error initializing cubeb library";
     98 
     99  std::unique_ptr<cubeb, decltype(&cubeb_destroy)> cleanup_cubeb_at_exit(
    100      ctx, cubeb_destroy);
    101 
    102  output_params.format = CUBEB_SAMPLE_FLOAT32LE;
    103  output_params.rate = 48000;
    104  output_params.channels = 2;
    105  output_params.layout = CUBEB_LAYOUT_STEREO;
    106  output_params.prefs = CUBEB_STREAM_PREF_NONE;
    107 
    108  r = cubeb_get_min_latency(ctx, &output_params, &latency_frames);
    109  if (r != CUBEB_OK) {
    110    // not fatal
    111    latency_frames = 1024;
    112  }
    113 
    114  r = cubeb_stream_init(ctx, &stream, "Cubeb logging", NULL, NULL, NULL,
    115                        &output_params, latency_frames, data_cb_load, state_cb,
    116                        NULL);
    117  ASSERT_EQ(r, CUBEB_OK) << "Error initializing cubeb stream";
    118 
    119  std::unique_ptr<cubeb_stream, decltype(&cubeb_stream_destroy)>
    120      cleanup_stream_at_exit(stream, cubeb_stream_destroy);
    121 
    122  ASSERT_NE(log_statements_received.load(std::memory_order_acquire), 0u);
    123 
    124  cubeb_set_log_callback(CUBEB_LOG_DISABLED, nullptr);
    125  log_statements_received.store(0, std::memory_order_release);
    126 
    127  // This is synchronous and we'll receive log messages on all backends that we
    128  // test
    129  cubeb_stream_start(stream);
    130 
    131  ASSERT_EQ(log_statements_received.load(std::memory_order_acquire), 0u);
    132 
    133  cubeb_set_log_callback(CUBEB_LOG_VERBOSE, test_logging_callback);
    134 
    135  wait_for_audio_callback();
    136 
    137  ASSERT_NE(log_statements_received.load(std::memory_order_acquire), 0u);
    138 
    139  bool log_callback_set = true;
    140  uint32_t iterations = 100;
    141  while (iterations--) {
    142    wait_for_audio_callback();
    143 
    144    if (!log_callback_set) {
    145      ASSERT_EQ(log_statements_received.load(std::memory_order_acquire), 0u);
    146      // Set a logging callback, start logging
    147      cubeb_set_log_callback(CUBEB_LOG_VERBOSE, test_logging_callback);
    148      log_callback_set = true;
    149    } else {
    150      // Disable the logging callback, stop logging.
    151      ASSERT_NE(log_statements_received.load(std::memory_order_acquire), 0u);
    152      cubeb_set_log_callback(CUBEB_LOG_DISABLED, nullptr);
    153      log_statements_received.store(0, std::memory_order_release);
    154      // Disabling logging should flush any log message -- wait a bit and check
    155      // that this is true.
    156      ASSERT_EQ(log_statements_received.load(std::memory_order_acquire), 0u);
    157      log_callback_set = false;
    158    }
    159  }
    160 
    161  cubeb_stream_stop(stream);
    162 }
    163 
    164 TEST(cubeb, logging_stress)
    165 {
    166  cubeb_set_log_callback(CUBEB_LOG_NORMAL, test_logging_callback);
    167 
    168  std::atomic<bool> thread_done = {false};
    169 
    170  auto t = std::thread([&thread_done]() {
    171    uint32_t count = 0;
    172    do {
    173      while (rand() % 10) {
    174        ALOG("Log message #%d!", count++);
    175      }
    176    } while (count < 1e4);
    177    thread_done.store(true);
    178  });
    179 
    180  bool enabled = true;
    181  while (!thread_done.load()) {
    182    if (enabled) {
    183      cubeb_set_log_callback(CUBEB_LOG_DISABLED, nullptr);
    184      enabled = false;
    185    } else {
    186      cubeb_set_log_callback(CUBEB_LOG_NORMAL, test_logging_callback);
    187      enabled = true;
    188    }
    189  }
    190 
    191  cubeb_set_log_callback(CUBEB_LOG_DISABLED, nullptr);
    192 
    193  t.join();
    194 
    195  ASSERT_TRUE(true);
    196 }