HelloThisIsFlo / Appdaemon-Test-Framework

Clean, human-readable tests for Appdaemon
https://hellothisisflo.github.io/Appdaemon-Test-Framework/
MIT License
45 stars 19 forks source link

Add support for all time based schedulers in AppDaemon #18

Closed lifeisafractal closed 5 years ago

lifeisafractal commented 5 years ago

Currently, only run_in is support by the test framework. It would be great for testing if all scheduler calls were supported as well as dispatching these callbacks. Additional, a more expressive API for moving through time in tests would help cover more test cases I'm interned in when TDD'ing my tests.

I'm currently working on a branch with some ideas of how to approach this if you want ot have a look: https://github.com/FlorianKempenich/Appdaemon-Test-Framework/compare/master...lifeisafractal:expand_time_travel

I'd like to discuss design decisions here before I get too far down the wrong path, but I'm also happy puttering along on this (hey, it's fun!).

General design thoughts:

I'll keep putting along on my branch, but I'd love to talk about why this is needed and how to implement it as I'm going along on it.

Also, the intent would be to get this up for PR and merged, but then follow on with an extension that support sun related callbacks and calls.

HelloThisIsFlo commented 5 years ago

First of all, as always, I love your enthusiasm 😃

I think expanding the time capabilities is a great idea! One that I wanted to tackle a while ago, but didn't end up having time to implement. And now, I don't have the use-case anymore. That would be nice but not enough for me to spend too much time on it. So when I saw, you were taking a shot at it, I was more than pleasantly surprised 😊

Make the time_travel fixture the central place for handling all time and callback scheduling.

👍

Rather than mocking each call (run_hourly, run_at, etc.), mock lower level AD APIs so we can reuse the appapi implementations and logic. (i.e. appapi.insert_schedule)

That was one of my original ideas, but after looking a bit into it I concluded it wasn't worth the hassle for my use-case at the time. If you find a way to build it, and if it's reliable enough, then Hell yeah, go for it !!

Proposed breaking change: remove given_that.time_is() and replace with time_travel.reset_time().

I see the rationale, however I'm not sure keeping the current API would necessarily mean cutting corners on code quality. Here is how I see it:

So I would be into keeping given_that.time_is(...).

Now, would that necessarily mean breaking encapsulation in nasty ways? Not necessarily:

With one of these alternative we would have:

Anyway, let me know what you think 😉 Also, important: I want you to have fun when working on this. So if you disagree with whatever I'm saying, it's totally cool, let's have a discussion, that's what this place is for 🙂 All I'm saying is: Never go with a decision you don't agree with, let's talk until we find a compromise we're both happy with (and I guarantee, if we're patient, we always will ;) )

lifeisafractal commented 5 years ago

I think you're on to something there with that new code structuring! I think factoring out internal helper fixtures to hold state is a great answer and can keep the current test API the same. I also agree that given_that makes most sense for setting stuff up. I wanted to get there, but couldn't quite figure it out on my own.

I'll keep working on my branch and post a PR when I have something work talking about.

Also, thanks for the last comment. I'm for sure having fun and you've been a please to work with :).

lifeisafractal commented 5 years ago

I scrapped what I had and took another stab at this based on the discussion above and overall I'm really happy with how it's coming out. I've hit one real problem I can't get through.

With full simulation all scheduler types, you can't just jump around in time without possibly misrepresenting the true state of things (both scheduled events and states). This means, you need to set the start time prior to scheduling any callbacks, which practically means before you .initialize() the automation. The current pattern of calling initialize() in the test fixture setup makes this pretty clunky. If you want to set the start time to different things for different tests this makes it pretty complicated.

Do you have any thoughts? I'll keep playing around with it, but I'm not sure how to do this with the least breaking impact.

lifeisafractal commented 5 years ago

FYI, here is the new branch I'm working on if you want to take a look at it: https://github.com/FlorianKempenich/Appdaemon-Test-Framework/compare/master...lifeisafractal:expand_time_travel_take2

HelloThisIsFlo commented 5 years ago

(quick update on my status)

I'm currently in the process of moving cities, countries even, without a job lined up. It's something I'm used to doing, so all good, but it does mean that my availabilities are really sparse for the next few weeks.

I read all your comments but didn't yet find the time to check out your branch to play with your implementation. I'll take a deeper look when I find some downtime on my side, I just don't know if it's going to be in 2 days or in 2 months (both being extremes ;) ) Anyway, just wanted to let you know that even though I don't answer, I do read everything and follow your progress, from a distance 😊

You'll hear more from me .... when you'll hear more from me 😊

lifeisafractal commented 5 years ago

thanks for the update. I'll keep working on that branch. Good luck with the move!

lifeisafractal commented 5 years ago

Quick follow up: I've made some great progress that is moving in on some reviewable code. I need to up date the docs (which will help digesting the PR also), and need to re-vamp the existing example integration tests to fit some of the new patterns better. Once I get those done, I'll open a PR so we can begin discussion against the code. This is going to be a bigger one so I'm ready for some serious iteration to get to a point where we're all happy.

HelloThisIsFlo commented 5 years ago

I'm closing this, let's continue the discussion on the PR ;)