Coder Social home page Coder Social logo

Comments (17)

tcldr avatar tcldr commented on July 19, 2024 1

Yeah, it needs to be the branch of the PR for this issue:
package(url: "[email protected]: tcldr/Entwine.git", .branch("test-scheduler-intervals"))

from entwine.

iwheelbuy avatar iwheelbuy commented on July 19, 2024 1

After switching between PR branch, 0.9.0 tag and back - It started to pass successfully.....
I wonder if it was a SPM bug/cache

I'll do some more research, thank you for your reply.

from entwine.

tcldr avatar tcldr commented on July 19, 2024

Hi – thanks for the report. Yes, looks like there was an issue with the TestScheduler that meant it failed to schedule any repeating actions – which is required by Combine's CollectByTime publisher. I've posted a fix on a branch called test-scheduler-intervals attached to PR #26. Let me know if that resolves your issue.

from entwine.

iwheelbuy avatar iwheelbuy commented on July 19, 2024

It works, thanks a lot!

from entwine.

iwheelbuy avatar iwheelbuy commented on July 19, 2024

Or maybe it doesn't...
I decided to test Debounce

let upstream: TestablePublisher<String, TestError> = scheduler.createRelativeTestablePublisher([
   (1, .input("a")),
   (2, .input("b")),
   (7, .input("c")),
   (99, .completion(.finished))
])
let publisher = Publishers.Debounce(
   upstream: upstream,
   dueTime: 5,
   scheduler: scheduler,
   options: nil
)
let subscriber = scheduler.start(configuration: configuration, create: { publisher })

And got ["c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c"] events.
Please don't waste your time if it's not an easy feature to implement.

from entwine.

tcldr avatar tcldr commented on July 19, 2024

Not at all. Good to get the issues ironed out. Try the latest commit to PR #26

from entwine.

iwheelbuy avatar iwheelbuy commented on July 19, 2024

There is still something wrong with it...

interval = 12
count = 5
values = [1, 5, 7, 11, 13, 27, 35, 43, 51, 53, 55, 61, 67, 69, 73, 77, 79, 83, 87, 89, 91, 93, 95]

With test scheduler I got:

[[1, 5, 7, 11, 13], [27, 35, 43, 51, 53], [55, 61], [67, 69, 73, 77, 79]]

As you can see [27, 35, 43, 51, 53] is not correct because 53 - 27 > 12. Also some values are lost.

I've written the function which produces the expected answer and the result should be:

[[1, 5, 7, 11], [13], [27, 35], [43], [51, 53, 55], [61, 67, 69], [73, 77, 79, 83], [87, 89, 91, 93, 95]]

I've tested the "expected answer" function and CollectByTime publisher with ordinary DispatchQueue.global(qos: .userInteractive) and got the result which matches with "expected answer" function result.

P.S. I think there is something wrong with the approach to repeating actions. I'm going to continue without test scheduler for CollectByTime publisher for now. Maybe will come back later.

P.S. Debounce publisher works correct in master

P.S. I have created a test-scheduler-intervals branch in my test repository in case you want to try those tests yourself.

from entwine.

tcldr avatar tcldr commented on July 19, 2024

Hi @iwheelbuy, thanks for writing this up – I really appreciate it! However, when I run your example numbers, it matches the control.

As you can see [27, 35, 43, 51, 53] is not correct because 53 - 27 > 12. Also some values are lost.

I'm not sure our understanding CollectByTime matches up.

My understanding of CollectByTime is that: when using the 'time' strategy, it will collect all elements from the point the publisher started to the point the interval has elapsed. So if using an interval of 5, it will group all elements between 0..<5, 5..<10, 10..<15 and so on. (With 'zero' being the time at which the publisher was subscribed to.)

When also specifying count as part of the strategy, the behaviour is the same, except that if the count is reached within a time interval (0..<5 or 5..<10), the publisher will immediately output the elements it has already collected for that time interval, but otherwise continue as normal.

As an example, if we schedule [0,1,2,3,4,5,6,7,8,9] to be published with an interval of 5, and a count of 5, we will receive [[0,1,2,3,4],[5,6,7,8,9]] and if we ask for an interval of 5 and count of 2 we will receive [[0,1],[2,3],[4],[5,6],[7,8],[9]].

As the interval is determined by the subscribe time, if we offset everything by 3 ([3,4,5,6,7,8,9,10,11,12]), with an interval of 5 and a count of 5, we will receive [[3,4],[5,6,7,8,9],[10,11,12]] and if we ask for an interval of 5 and count of 2 we will receive [[3,4],[5,6],[7,8],[9],[10,11],[12]].

Using your own example, we can test without Entwine using a control by:

    func testControlCollectByTimeSequence() {
        let interval = 12
        let count = 5
        let expected = [
            [1, 5, 7, 11],
            [13],
            [27, 35],
            [43],
            [51, 53, 55],
            [61, 67, 69],
            [73, 77, 79, 83],
            [87, 89, 91, 93, 95],
        ]
        let sut = DispatchQueue(label: "serial-queue")
        let subject = PassthroughSubject<Int, Never>()
        let strategy = Publishers.TimeGroupingStrategy<DispatchQueue>
            .byTimeOrCount(sut, .init(.milliseconds(interval)), count)
        let publisher = Publishers.CollectByTime(upstream: subject, strategy: strategy, options: nil)
        var cancellables = Set<AnyCancellable>()
        var results = [[Int]]()
        
        publisher.sink(receiveValue: { results.append($0) }).store(in: &cancellables)
        
        let testIntervals = expected.flatMap { $0 }
        
        let now = DispatchTime.now()
        let group = DispatchGroup()
        group.enter()
        sut.schedule(after: .init(now + .milliseconds(1000))) { group.leave() }
        for interval in testIntervals {
            sut.schedule(after: .init(now + .milliseconds(interval))) { subject.send(interval) }
        }
        _ = group.wait(timeout: now + .milliseconds(2000))
        
        XCTAssertEqual(expected, results)
    }

And with Entwine, we have:

    func testCollectByTimeSequence() {
        let interval = 12
        let count = 5
        let expected = [
            [1, 5, 7, 11],
            [13],
            [27, 35],
            [43],
            [51, 53, 55],
            [61, 67, 69],
            [73, 77, 79, 83],
            [87, 89, 91, 93, 95],
        ]
        
        let sut = TestScheduler(initialClock: 0, maxClock: 2000)
        let strategy = Publishers.TimeGroupingStrategy<TestScheduler>
            .byTimeOrCount(sut, .init(interval), count)
        let subject = PassthroughSubject<Int, Never>()
        let publisher = Publishers.CollectByTime(upstream: subject, strategy: strategy, options: nil)
        var cancellables = Set<AnyCancellable>()
        var results = [[Int]]()
        
        publisher.sink(receiveValue: { results.append($0) }).store(in: &cancellables)
        
        let testIntervals = expected.flatMap { $0 }
        
        for interval in testIntervals {
            sut.schedule(after: .init(interval)) { subject.send(interval) }
        }
        sut.resume()
        
        XCTAssertEqual(expected, results)
    }

Were you expecting something different?

from entwine.

iwheelbuy avatar iwheelbuy commented on July 19, 2024

Our understanding matches up! It was me who made a mistake. Values 1, 5, 7, 11, 13... represent not just values, but also a time when to publish the value. I have accidentally replaced time of value with number of index in array...

I'll check again (^

from entwine.

iwheelbuy avatar iwheelbuy commented on July 19, 2024

As I've mentioned 1, 5, 7, 11, 13... represents a value and a virtual time when to publish. It means I publish Int(13) on VirtualTime(13). So I've corrected the time each value is published. The new result I got is:

[[1, 5, 7, 11], [13, 27, 35, 43, 51], [53, 55, 61, 67, 69]]

The first emitted array [1, 5, 7, 11] is okay because it matches the 0 ..< 12 time interval and array size of 5 not reached.
The second array we expect to be in 12 ..< 24 time interval. And there is only one item from values which matches the range, it is 13. So I expect that the second emitted array should be [13]. But it is not...

from entwine.

tcldr avatar tcldr commented on July 19, 2024

Thanks for checking! If you run this test:

func testCollectByTimeSequence() {
        let interval = 12
        let count = 5
        let expected = [
            [1, 5, 7, 11],
            [13],
            [27, 35],
            [43],
            [51, 53, 55],
            [61, 67, 69],
            [73, 77, 79, 83],
            [87, 89, 91, 93, 95],
        ]
        
        let sut = TestScheduler(initialClock: 0, maxClock: 2000)
        let strategy = Publishers.TimeGroupingStrategy<TestScheduler>
            .byTimeOrCount(sut, .init(interval), count)
        let subject = PassthroughSubject<Int, Never>()
        let publisher = Publishers.CollectByTime(upstream: subject, strategy: strategy, options: nil)
        var cancellables = Set<AnyCancellable>()
        var results = [[Int]]()
        
        publisher.sink(receiveValue: { results.append($0) }).store(in: &cancellables)
        
        let testIntervals = expected.flatMap { $0 }
        
        for interval in testIntervals {
            sut.schedule(after: .init(interval)) { subject.send(interval) }
        }
        sut.resume()
        
        XCTAssertEqual(expected, results)
    }

What do you get?

from entwine.

iwheelbuy avatar iwheelbuy commented on July 19, 2024

package(url: "[email protected]:iwheelbuy/Entwine.git", .branch("test-scheduler-intervals"))

XCTAssertEqual failed: ("[[1, 5, 7, 11], [13], [27, 35], [43], [51, 53, 55], [61, 67, 69], [73, 77, 79, 83], [87, 89, 91, 93, 95]]") is not equal to ("[[1, 5, 7, 11], [13, 27, 35, 43, 51], [53, 55, 61, 67, 69], [73, 77, 79, 83, 87]]")

from entwine.

tcldr avatar tcldr commented on July 19, 2024

Curious – that passes for me. Are you testing against the latest test-scheduler-intervals commit?

from entwine.

iwheelbuy avatar iwheelbuy commented on July 19, 2024

Checked also on .package(url: "[email protected]:tcldr/Entwine.git", from: "0.9.0"), same result

XCTAssertEqual failed: ("[[1, 5, 7, 11], [13], [27, 35], [43], [51, 53, 55], [61, 67, 69], [73, 77, 79, 83], [87, 89, 91, 93, 95]]") is not equal to ("[[1, 5, 7, 11], [13, 27, 35, 43, 51], [53, 55, 61, 67, 69], [73, 77, 79, 83, 87]]")

from entwine.

tcldr avatar tcldr commented on July 19, 2024

No problem, let me know if it works out and I'll merge this into master. Thanks!

from entwine.

iwheelbuy avatar iwheelbuy commented on July 19, 2024

Everything works!

from entwine.

tcldr avatar tcldr commented on July 19, 2024

Great news! Glad it worked out.

from entwine.

Related Issues (15)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.