How to unit-test a infinite while loop in python - pytest

class A:
def exe(self):
x= threading.Event()
y= threading.Thread(name=A, target=self.infi, args=(x,), daemon=True)
y.start()
def infi(self,x):
while True:
......
start=True
if start:
start = False
x.set()
time.sleep(5)
I wanted to test the exe method inside class A, but the infi method is having an infinite loop so there is no way exit or to stop the code if I wanted to test exec method how should I do it. Can I break the while if so how to do it.

Related

How do you test a celery chord in a django app from inside of pytest?

Using:
celery==5.2.7
django-celery-results==2.4.0
django==4.1
pytest==7.1.2
pytest-django==4.5.2
pytest-celery==0.0.0
I'm trying to test a task (start_task) that creates a chord (of N work_task tasks) with a callback task to summarize the work.
def test_function(db):
...
obj = make_obj
...
start_task.delay(obj)
I call start_task which creates a single work_task. The chord never
completes so that the summarize_task gets called. The work_task completes successfully (I can see that in the debugger). When I modify the test to:
def test_function(db, celery_app, celery_worker):
...
obj = make_obj
...
start_task.delay(obj)
The test dies on make_obj because the db connection is already closed.
E psycopg2.InterfaceError: connection already closed
My work around for the moment is to manually call tasks so that celery is not involved, but this does not test the chord mechanisms, only the logic that is invoked by the chord.
If someone has an example
It can be done using UnitTest style tests with pytest. I haven't solved this using native pytest yet. The secret sauce below is to use a TransactionTestCase vs a normal Django TestCase
from django.test import TransactionTestCase, override_settings
#pytest.mark.xdist_group(name="celery")
#override_settings(CELERY_TASK_ALWAYS_EAGER=False)
#override_settings(CELERY_TASK_EAGER_PROPAGATES=False)
class SyncTaskTestCase2(TransactionTestCase):
#classmethod
def setUpClass(cls):
super().setUpClass()
cls.celery_worker = start_worker(app, perform_ping_check=False)
cls.celery_worker.__enter__()
print(f"Celery Worker started {time.time()}")
#classmethod
def tearDownClass(cls):
print(f"Tearing down Superclass {time.time()}")
super().tearDownClass()
print(f"Tore down Superclass {time.time()}")
cls.celery_worker.__exit__(None, None, None)
print(f"Celery Worker torn down {time.time()}")
def test_success(self):
print(f"Starting test at {time.time()}")
self.task = do_average_in_chord.delay()
self.task.get()
print(f"Finished Averaging at {time.time()}")
assert self.task.successful()
cls.celery_work.__exit__(None, None, None) takes about 9 seconds to complete which is not particularly wonderful....

How to mock MVar2 make method

I'm having trouble mocking the MVar2 method make in my Unit test (using mockito).
I tried this:
private val sq = mock[MVar2[IO, String]]
and when I tried to mock the method like:
when(sq.take).thenReturn(
"testString".pure[IO],
IO.never
)
I get the infinite loop in the test.
I was positive I could mock it like this.
The actual code calling the make is:
def run: F[Unit] =
fs2.Stream
.repeatEval[F, String](signalQ.take)
.map(encode)
.unNone
.evalTap(logMessage)
.evalMap(send)
.compile
.drain
I see two issues.
The first thing, there is no reason to mock IO. You can pretty much do this:
// define this wherever you create sq
val sq = MVar2[IO, String]
// then DI sq and
sq.put("testString") >> run
Then the second thing, how does .repeatEval(io) works? It calls io repeatedly, every time the stream needs another element. So at first it would evaluate io with your mock to:
"testString".pure[IO]
which would compute the first element to "testString" and later to
IO.never
which means that the second element would never appear as this io would never return - neither value nor exception. And your stream halts as you can see. (Which would be according to the spec but apparently not what you want).
If you wanted to get Some(string) if value is present and None if it's absent (to terminate stream on None) you should try:
def run: F[Unit] =
fs2.Stream
.repeatEval[F, Option[String]](signalQ.tryTake)// <-- try to get None on empty
.unNoneTerminate // <-- terminate on None
.map(encode)
.evalTap(logMessage)
.evalMap(send)
.compile
.drain

Calling slow future returning function in scala for each item in a Seq

I have this sample code currently but the issue is that slowFunction() below isn't running at all.
Is it possible to trigger the next function call after the function call on the previous item returns? It doesn't really matter as long as the function gets executed at least once for each item but thought it would help with the load on the system.
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Failure, Success}
val inputsFromDb = Future { Seq(1, 2, 3) }
def slowFunction(input: Int): Future[Boolean] = {
Future {
Thread.sleep(1000)
println(s"Returning from slow function for input $input")
true
}
}
val results: Future[Boolean] = inputsFromDb.flatMap { inputs =>
val updateResults = inputs.map { input =>
println(s"Calling slow function for input $input")
slowFunction(input)
}
Future.sequence(updateResults).map(_ => true)
}
results // Future(<not completed>)
Here's the output if I run the code as is.
Calling slow function for input 1
Calling slow function for input 2
Calling slow function for input 3
However it runs fine when I comment out the sleep part Thread.sleep(1000)
Calling slow function for input 1
Calling slow function for input 2
Calling slow function for input 3
Returning from slow function for input 3
Returning from slow function for input 2
Returning from slow function for input 1
If I can't get this working, I might just add a delay between each call to slowFuction by using java.util.Timer
It looks like your program (or worksheet) is terminating before all the Futures reach completion.
Your code produces the expected output if, at some point before the program exits, you Await until results completes.
import scala.concurrent.duration._
scala.concurrent.Await.result(results, 999.millis)
As demonstrated in this Scastie session.

Use custom client protocol for pytest

I'm trying to use locust as a pytest library to write stress tests, but I have encountered some problems, and I can't solve them after several hours.
There are some assert statements in my pytest. I hope that when the assert statement reports an error, the locust will be stopped immediately and the test will be marked as failed.
class StressRobot(User):
wait_time = between(0.01, 0.1)
__robot = None
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
#task
def execute(self):
try:
logging.debug("do some stress test")
assert False
except Exception as e:
events.request_failure.fire()
#pytest.mark.stress
def test():
env = Environment(user_classes=[StressRobot])
env.create_local_runner()
env.runner.start(10, spawn_rate=10)
gevent.spawn_later(5, lambda: env.runner.quit())
env.runner.greenlet.join()
assert env.stats.num_failures == 0
My code is like the above. I hope that when assert False, the pytest case will end immediately, and assert env.stats.num_failures == 0 will report an error. But he is not over, he will keep running, keep reporting errors, and will not end until 5 seconds later, and finally env.stats.num_failures == 0
A failure does not stop a locust run.
In your task you can call self.environment.runner.quit() (instead of just logging a request failure event)
See https://docs.locust.io/en/stable/writing-a-locustfile.html#environment-attribute

If-else without else causes recursive function to repeat

Why does the following produce the output "ayyayy" and not just "ayy" (once)?
def iftest(b: Boolean): Unit = {
if(b) iftest(false)
print("ayy")
}
I run it in REPL as iftest(true) which should cause it to fail on the first pass but succeed on the second (hence only one "ayy"). So why does it act like both succeed?
Is there some sort of recursive "backfolding" in scala that I don't know about?
Is there some sort of recursive "backfolding" in scala that I don't
know about?
No, the method operates as you've defined it. Lets analyze:
You call iftest(true) and invoke the method.
if(b) is true, so you call iftest(false) and start a new stack frame.
if(b) is now false, so we don't recursively call the method again.
The next line of code is print("ayy"), so it prints it out and the method completes
We go back up one frame, we now finished calling iftest(false) and the next line of code is println("ayy"), so it prints it out again
Method completes.
Perhaps what you want is:
def iftest(b: Boolean): Unit = {
if (b) {
iftest(false)
print("ayy")
}
}