TestThreadReschedule -- how?

I have been working on a feature to allow Routines and all types of PauseStreams to be rescheduled while playing (based on a discussion of a different issue). With it, you can call aThread.reschedule(clock, time) and move the thread to a different clock, or a different time, or both.

Before I submit the PR, I need to write a unit test. I just tried one approach, but it isn’t correct – measuring the thread timing doesn’t work as I expected.

Issues of thread timing are, in my experience, the most difficult for unit testing. (I intend “difficult” as a euphemism here. I find the constraints, frankly, painful enough to be a disincentive to contribute.)

So I’m going to ask for advice. What would be the best way to test this feature? Code is mainly here, with some backend support.

Usage example:

c = TempoClock.new;

d = TempoClock(2);  // run these at different times

(
t = Task {
	loop {
		[thisThread.beats, thisThread.seconds].postln;
		1.0.wait;
	};
}.play(c, quant: 1);
)

t.reschedule(d);

t.stop; c.stop; d.stop;

WIth output:

[ 22.0, 4128.605112713 ]
[ 23.0, 4129.605112713 ]
[ 24.0, 4130.605112713 ]
[ 25.0, 4131.605112713 ]
-> a Task

// here, the previous iteration asked to wait one beat,
// in the old tempo, before the next.
// That's one second, per c's tempo.
// So the next line shows d's beats at the next desired 'seconds' value.

[ 50.426778592, 4132.605112713 ]
[ 51.426778592, 4133.105112713 ]
[ 52.426778592, 4133.605112713 ]
[ 53.426778592, 4134.105112713 ]
[ 54.426778592, 4134.605112713 ]

hjh

Hi!
Wouldn’t it be enough to check if the clock was changed?

In hope it can be inspiring in any way, here is a test I wrote for a related issue:

test_playOnInstanceClock {
        var actualClock;
        var clock = TempoClock(2);
        var cond = Condition();
        var proxy = EventPatternProxy(
            Pbind(\dummy, Pfuncn{ actualClock = thisThread.clock; cond.unhang }, \dur, 0)
        );
        proxy.clock_(clock).play;
        cond.hang;
        this.assertEquals(actualClock, clock, "EventPatternProxy.play() should use instance's clock if no argClock is given");
    }

}

The difference is that we would have to wait for thisThread.clock to equal d (or a timeout) before unhanging.
I’m also thinking about a way to test for “double scheduling”: maybe the task could store (thisThread.clock === d) in a list, the last n elements of which should all be true…

sorry for sketchy thoughts, not much time today, but I’m happy you’re doing it, and hope this can be useful to you somehow!

Or maybe even something like this?

(
{
    var origClock = TempoClock.new(10);
    var newClock = TempoClock.new(9);
    var condition = Condition();
    var resultClocks = List[];
    var task; 
    
    task = Task {
        resultClocks.add(thisThread.clock);
        task.reschedule(newClock);
        0.wait;
        resultClocks.add(thisThread.clock);
        condition.unhang;
    }.play(origClock, quant: 1);
    
    condition.hang();
    "Original: %".format(resultClocks[0] == origClock).postln;
    "Rescheduled: %".format(resultClocks[1] == newClock).postln;

}.fork
)

Still thinking about it. Thanks for the suggestions.

I think it’s necessary to test the timing – if a future change makes it switch clock correctly, but at the wrong time, we should have proof of it.

I guess the first step is that I need to be sure of the exact sequence of wakeups and beat/second values – my problem this afternoon may have been that I wasn’t totally sure when/how the test thread wakes up relative to the control thread, and I didn’t write the control thread correctly. More research later…

hjh