<commit_before>package com.twitter.finagle.mux.lease.exp

import com.twitter.util._
import com.twitter.util.Local.Context
import com.twitter.conversions.storage.intToStorageUnitableWholeNumber
import com.twitter.conversions.time.intToTimeableNumber
import org.junit.runner.RunWith
import org.scalatest.concurrent.Eventually
import org.scalatest.FunSuite
import org.scalatest.junit.JUnitRunner
import scala.util.Random

@RunWith(classOf[JUnitRunner])
class WindowedByteCounterTest extends FunSuite with Eventually {
  trait ByteCounterHelper {
    val fakePool = new FakeMemoryPool(new FakeMemoryUsage(StorageUnit.zero, StorageUnit.zero))
    val fakeBean = new FakeGarbageCollectorMXBean(0, 0)
    val nfo = new JvmInfo(fakePool, fakeBean)
  }

  // cleans up thread
  def withCounter(fakeBean: FakeGarbageCollectorMXBean, fakePool: FakeMemoryPool)(
    fn: (ByteCounter, () => Unit) => Unit
  ): Unit = {
    Time.withCurrentTimeFrozen { ctl =>
      val nfo = new JvmInfo(fakePool, fakeBean)
      val counter = new WindowedByteCounter(nfo, Local.save())
      eventually {
        assert(counter.getState === Thread.State.TIMED_WAITING)
      }

      @volatile var closed = false
      @volatile var prev = -1
      val nextPeriod = { () =>
        eventually {
          assert(counter.getState === Thread.State.TIMED_WAITING)
        }
        ctl.advance(WindowedByteCounter.P)
        eventually {
          assert(counter.passCount != prev)
        }

        prev = counter.passCount

        if (!closed) eventually {
          assert(counter.getState === Thread.State.TIMED_WAITING)
        }
      }

      fn(counter, nextPeriod)

      counter.close()
      closed = true
      nextPeriod()

      counter.join()
    }
  }

  test("ByteCounter should be stoppable") {
    val h = new ByteCounterHelper{}
    import h._

    Time.withCurrentTimeFrozen { ctl =>
      val counter = new WindowedByteCounter(nfo, Local.save())

      assert(counter.close().poll === Some(Return(())))

      counter.join()
      assert(counter.isAlive === false)
    }
  }

  test("ByteCounter should give a trivial rate without info") {
    val h = new ByteCounterHelper{}
    import h._

    withCounter(fakeBean, fakePool) { case (counter, _) =>
      assert(counter.rate() === 0)
    }
  }

  test("ByteCounter should accurately measure rate") {
    val h = new ByteCounterHelper{}
    import h._

    withCounter(fakeBean, fakePool) { case (counter, nextPeriod) =>
      val usage = new FakeMemoryUsage(0.bytes, 10.megabytes)
      for (i <- 0 until WindowedByteCounter.N) {
        fakePool.setSnapshot(usage.copy(used = (1 + i).kilobytes))
        nextPeriod()
      }

      assert(counter.rate() === (WindowedByteCounter.N.kilobytes).inBytes / WindowedByteCounter.W.inSeconds)
    }
  }

  test("ByteCounter should support a windowed rate") {
    val h = new ByteCounterHelper{}<commit_msg>[split] marks another WindowedByteCounter test flaky<commit_after>package com.twitter.finagle.mux.lease.exp

import com.twitter.util._
import com.twitter.util.Local.Context
import com.twitter.conversions.storage.intToStorageUnitableWholeNumber
import com.twitter.conversions.time.intToTimeableNumber
import org.junit.runner.RunWith
import org.scalatest.concurrent.Eventually
import org.scalatest.FunSuite
import org.scalatest.junit.JUnitRunner
import scala.util.Random

@RunWith(classOf[JUnitRunner])
class WindowedByteCounterTest extends FunSuite with Eventually {
  trait ByteCounterHelper {
    val fakePool = new FakeMemoryPool(new FakeMemoryUsage(StorageUnit.zero, StorageUnit.zero))
    val fakeBean = new FakeGarbageCollectorMXBean(0, 0)
    val nfo = new JvmInfo(fakePool, fakeBean)
  }

  // cleans up thread
  def withCounter(fakeBean: FakeGarbageCollectorMXBean, fakePool: FakeMemoryPool)(
    fn: (ByteCounter, () => Unit) => Unit
  ): Unit = {
    Time.withCurrentTimeFrozen { ctl =>
      val nfo = new JvmInfo(fakePool, fakeBean)
      val counter = new WindowedByteCounter(nfo, Local.save())
      eventually {
        assert(counter.getState === Thread.State.TIMED_WAITING)
      }

      @volatile var closed = false
      @volatile var prev = -1
      val nextPeriod = { () =>
        eventually {
          assert(counter.getState === Thread.State.TIMED_WAITING)
        }
        ctl.advance(WindowedByteCounter.P)
        eventually {
          assert(counter.passCount != prev)
        }

        prev = counter.passCount

        if (!closed) eventually {
          assert(counter.getState === Thread.State.TIMED_WAITING)
        }
      }

      fn(counter, nextPeriod)

      counter.close()
      closed = true
      nextPeriod()

      counter.join()
    }
  }

  test("ByteCounter should be stoppable") {
    val h = new ByteCounterHelper{}
    import h._

    Time.withCurrentTimeFrozen { ctl =>
      val counter = new WindowedByteCounter(nfo, Local.save())

      assert(counter.close().poll === Some(Return(())))

      counter.join()
      assert(counter.isAlive === false)
    }
  }

  test("ByteCounter should give a trivial rate without info") {
    val h = new ByteCounterHelper{}
    import h._

    withCounter(fakeBean, fakePool) { case (counter, _) =>
      assert(counter.rate() === 0)
    }
  }

  test("ByteCounter should accurately measure rate") {
    val h = new ByteCounterHelper{}
    import h._

    withCounter(fakeBean, fakePool) { case (counter, nextPeriod) =>
      val usage = new FakeMemoryUsage(0.bytes, 10.megabytes)
      for (i <- 0 until WindowedByteCounter.N) {
        fakePool.setSnapshot(usage.copy(used = (1 + i).kilobytes))
        nextPeriod()
      }

      assert(counter.rate() === (WindowedByteCounter.N.kilobytes).inBytes / WindowedByteCounter.W.inSeconds)
    }
  }

  if (!sys.props.contains("SKIP_FLAKY")) test("ByteCounter should support a windowed rate") {
    val h = new ByteCounterHelper{}
{'fraction_non_alphanumeric': 0.10862892223738063, 'fraction_numerical': 0.0030695770804911324, 'mean_word_length': 3.0956703910614527, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6545720', 'n_tokens_mistral': 1813, 'n_tokens_neox': 1755, 'n_words': 384}