Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Refreshing the poll when receiving pollEnd can break the chronological order in the store. #1776

Merged
merged 6 commits into from
Apr 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions MatrixSDK/Aggregations/MXAggregations.m
Original file line number Diff line number Diff line change
Expand Up @@ -315,8 +315,6 @@ - (void)registerListener
[self.beaconAggregations handleBeaconWithEvent:event];
}
break;
case MXEventTypePollEnd:
[self.aggregatedPollsUpdater refreshPollAfter:event];
default:
break;
}
Expand Down
57 changes: 32 additions & 25 deletions MatrixSDK/Room/Polls/PollAggregator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public class PollAggregator {
private var events: [MXEvent] = []
private var hasBeenEdited = false

public private(set) var poll: PollProtocol! {
public private(set) var poll: PollProtocol? {
didSet {
delegate?.pollAggregatorDidUpdateData(self)
}
Expand Down Expand Up @@ -88,10 +88,10 @@ public class PollAggregator {
throw PollAggregatorError.invalidPollStartEvent
}

try self.init(session: session, room: room, pollStartEventId: pollStartEventId, delegate: delegate)
self.init(session: session, room: room, pollStartEventId: pollStartEventId, delegate: delegate)
}

public init(session: MXSession, room: MXRoom, pollStartEventId: String, delegate: PollAggregatorDelegate? = nil) throws {
public init(session: MXSession, room: MXRoom, pollStartEventId: String, delegate: PollAggregatorDelegate? = nil) {
self.session = session
self.room = room
self.pollStartEventId = pollStartEventId
Expand All @@ -100,7 +100,9 @@ public class PollAggregator {

NotificationCenter.default.addObserver(self, selector: #selector(handleRoomDataFlush), name: .mxRoomDidFlushData, object: self.room)
setupEditListener()
try buildPollStartContent()
buildPollStartContent()

reloadPollData()
}

private func setupEditListener() {
Expand All @@ -111,34 +113,35 @@ public class PollAggregator {
return
}

do {
try self.buildPollStartContent()
} catch {
self.delegate?.pollAggregator(self, didFailWithError: PollAggregatorError.invalidPollStartEvent)
}
self.buildPollStartContent()
}
}

private func buildPollStartContent() throws {
guard let event = session.store.event(withEventId: pollStartEventId, inRoom: room.roomId),
let eventContent = MXEventContentPollStart(fromJSON: event.content),
eventContent.answerOptions.count >= Constants.minAnswerOptionCount
private func buildPollStartContent() {
let event = session.store.event(withEventId: pollStartEventId, inRoom: room.roomId)
tryUpdatePollStartedEvent(with: event)
if let pollStartedEvent = pollStartedEvent {
poll = pollBuilder.build(pollStartEventContent: pollStartEventContent,
pollStartEvent: pollStartedEvent,
events: events,
currentUserIdentifier: session.myUserId,
hasBeenEdited: hasBeenEdited)
}
}

private func tryUpdatePollStartedEvent(with event: MXEvent?) {
guard
let event = event,
let eventContent = MXEventContentPollStart(fromJSON: event.content),
eventContent.answerOptions.count >= Constants.minAnswerOptionCount
else {
throw PollAggregatorError.invalidPollStartEvent
delegate?.pollAggregator(self, didFailWithError: PollAggregatorError.invalidPollStartEvent)
return
}

pollStartedEvent = event
pollStartEventContent = eventContent

hasBeenEdited = (event.unsignedData.relations?.replace != nil)

poll = pollBuilder.build(pollStartEventContent: eventContent,
pollStartEvent: pollStartedEvent,
events: events,
currentUserIdentifier: session.myUserId,
hasBeenEdited: hasBeenEdited)

reloadPollData()
}

@objc private func handleRoomDataFlush(sender: Notification) {
Expand All @@ -157,8 +160,12 @@ public class PollAggregator {
return
}

self.events.removeAll()
self.tryUpdatePollStartedEvent(with: response.originalEvent)
if self.pollStartedEvent == nil {
return
}

self.events.removeAll()
self.events.append(contentsOf: response.chunk)

let eventTypes = [kMXEventTypeStringPollResponse, kMXEventTypeStringPollResponseMSC3381, kMXEventTypeStringPollEnd, kMXEventTypeStringPollEndMSC3381]
Expand All @@ -179,7 +186,7 @@ public class PollAggregator {
currentUserIdentifier: self.session.myUserId,
hasBeenEdited: self.hasBeenEdited)
} as Any

self.poll = self.pollBuilder.build(pollStartEventContent: self.pollStartEventContent,
pollStartEvent: self.pollStartedEvent,
events: self.events,
Expand Down
2 changes: 1 addition & 1 deletion MatrixSDKTests/MXCryptoSecretShareTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ - (void)testSecretShare
// -> She gets the secret
XCTAssertEqualObjects(sharedSecret, secret);
[expectation fulfill];

return YES;
} failure:^(NSError * _Nonnull error) {
XCTFail(@"The operation should not fail - NSError: %@", error);
[expectation fulfill];
Expand Down
34 changes: 17 additions & 17 deletions MatrixSDKTests/MXPollAggregatorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@ class MXPollAggregatorTest: XCTestCase {
func testAggregations() {
self.createScenarioForBobAndAlice { bobSession, aliceSession, bobRoom, aliceRoom, pollStartEvent, expectation in
self.delegate = PollAggregatorBlockWrapper(dataUpdateCallback: { pollAggregator in
XCTAssertEqual(self.pollAggregator.poll.answerOptions.first!.count, 2)
XCTAssertEqual(self.pollAggregator.poll.answerOptions.last!.count, 0)
XCTAssertEqual(self.pollAggregator.poll?.answerOptions.first!.count, 2)
XCTAssertEqual(self.pollAggregator.poll?.answerOptions.last!.count, 0)
expectation.fulfill()
})

self.pollAggregator = try! PollAggregator(session: bobSession, room: bobRoom, pollStartEventId: pollStartEvent.eventId)
self.pollAggregator = PollAggregator(session: bobSession, room: bobRoom, pollStartEventId: pollStartEvent.eventId)

let dispatchGroup = DispatchGroup()

Expand Down Expand Up @@ -74,14 +74,14 @@ class MXPollAggregatorTest: XCTestCase {
func testSessionPausing() {
self.createScenarioForBobAndAlice { bobSession, aliceSession, bobRoom, aliceRoom, pollStartEvent, expectation in
let delegate = PollAggregatorBlockWrapper(dataUpdateCallback: { aggregator in
XCTAssertEqual(aggregator.poll.answerOptions.first!.count, 2)
XCTAssertEqual(aggregator.poll.answerOptions.last!.count, 0)
XCTAssertEqual(aggregator.poll?.answerOptions.first!.count, 2)
XCTAssertEqual(aggregator.poll?.answerOptions.last!.count, 0)
})

self.pollAggregator = try! PollAggregator(session: bobSession, room: bobRoom, pollStartEventId: pollStartEvent.eventId)
self.pollAggregator = PollAggregator(session: bobSession, room: bobRoom, pollStartEventId: pollStartEvent.eventId)

XCTAssertEqual(self.pollAggregator.poll.answerOptions.first!.count, 1) // One from Alice
XCTAssertEqual(self.pollAggregator.poll.answerOptions.last!.count, 0)
XCTAssertEqual(self.pollAggregator.poll?.answerOptions.first!.count, 1) // One from Alice
XCTAssertEqual(self.pollAggregator.poll?.answerOptions.last!.count, 0)

bobSession.pause()

Expand All @@ -99,16 +99,16 @@ class MXPollAggregatorTest: XCTestCase {

func testGappySync() {
self.createScenarioForBobAndAlice { bobSession, aliceSession, bobRoom, aliceRoom, pollStartEvent, expectation in
self.pollAggregator = try! PollAggregator(session: bobSession, room: bobRoom, pollStartEventId: pollStartEvent.eventId)
self.pollAggregator = PollAggregator(session: bobSession, room: bobRoom, pollStartEventId: pollStartEvent.eventId)

self.delegate = PollAggregatorBlockWrapper(dataUpdateCallback: { aggregator in
XCTAssertEqual(aggregator.poll.answerOptions.first!.count, 2) // One from Bob and one from Alice
XCTAssertEqual(aggregator.poll.answerOptions.last!.count, 1) // One from Alice
XCTAssertEqual(aggregator.poll?.answerOptions.first!.count, 2) // One from Bob and one from Alice
XCTAssertEqual(aggregator.poll?.answerOptions.last!.count, 1) // One from Alice
expectation.fulfill()
})

XCTAssertEqual(self.pollAggregator.poll.answerOptions.first!.count, 1) // One from Alice
XCTAssertEqual(self.pollAggregator.poll.answerOptions.last!.count, 0)
XCTAssertEqual(self.pollAggregator.poll?.answerOptions.first!.count, 1) // One from Alice
XCTAssertEqual(self.pollAggregator.poll?.answerOptions.last!.count, 0)

bobSession.pause()

Expand All @@ -135,7 +135,7 @@ class MXPollAggregatorTest: XCTestCase {

func testEditing() {
self.createScenarioForBobAndAlice { bobSession, aliceSession, bobRoom, aliceRoom, pollStartEvent, expectation in
self.pollAggregator = try! PollAggregator(session: bobSession, room: bobRoom, pollStartEventId: pollStartEvent.eventId)
self.pollAggregator = PollAggregator(session: bobSession, room: bobRoom, pollStartEventId: pollStartEvent.eventId)

self.delegate = PollAggregatorBlockWrapper(dataUpdateCallback: { aggregator in
defer {
Expand All @@ -144,9 +144,9 @@ class MXPollAggregatorTest: XCTestCase {
guard self.isFirstDelegateUpdate else {
return
}
XCTAssertEqual(aggregator.poll.text, "Some other question")
XCTAssertEqual(aggregator.poll.answerOptions.count, 2)
XCTAssertTrue(aggregator.poll.hasBeenEdited)
XCTAssertEqual(aggregator.poll?.text, "Some other question")
XCTAssertEqual(aggregator.poll?.answerOptions.count, 2)
XCTAssertEqual(aggregator.poll?.hasBeenEdited, true)
expectation.fulfill()
})

Expand Down
1 change: 1 addition & 0 deletions changelog.d/pr-1776.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Poll: Refreshing the poll when receiving pollEnd can break the chronological order in the store.