-
Notifications
You must be signed in to change notification settings - Fork 12
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
POC - DBP Processor Refactoring (Abstraction & Testability) #2730
Conversation
…ete implementation. Add dependencies protocol and concrete impl.
…. This replaces our processor.
47bdf76
to
1b369a5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome work! I think this goes a really long way to moving us in the right direction
@@ -0,0 +1,81 @@ | |||
// | |||
// DataBrokerOperationsCollectionBuilder.swift |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the introduction of this class is awesome. One minor thing is it really highlights the need to rename DataBrokerOperationsCollection, since this is technically building a DataBrokerOperationsCollectionCollection.
It's my understanding that a DataBrokerOperationsCollection is all of the operations (even operation I think we should rename to avoid confusion with NSOperation) for a single broker. I think using that information if we first come up with a different name for scan/opt out "operations"we should be able to come up with a better name
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree on the need for renaming. I thought about this, and came up with different ideas -e.g renaming DataBrokerOperationsCollection
to DataBrokerJob
, or DataBrokerJobGroup
, and other variations. In the end, I decided that as DataBrokerOperationsCollection
is in fact an Operation
, and it is handled as such by an OperationQueue
, it should just be called DataBrokerOperation
. However, to implement this I needed to change conflicting type names.
Ultimately, what I propose is in this commit.
Note that we could go further with this - i.e rename other references to operation which should now say task based on these changes. At the moment I think we overuse ‘Operation’. However, want to share this and get input before we make any more related changes.
...okerProtection/Sources/DataBrokerProtection/Scheduler/DataBrokerProtectionQueueManager.swift
Show resolved
Hide resolved
...okerProtection/Sources/DataBrokerProtection/Scheduler/DataBrokerProtectionQueueManager.swift
Show resolved
Hide resolved
self.brokerUpdater = brokerUpdater | ||
} | ||
|
||
func startManualScans(showWebView: Bool, operationDependencies: OperationDependencies, completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd maybe change "startManualScans" to something like startManualScansIfPermitted, although they should always be. But since it does check for interruptions I think we should capture that somehow
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@THISISDINOSAUR what would be the cases for the manual scan to not start? In other words, how can it not be permitted? Is the depencency other scans running or initial data state, like, not having a profile data
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think at present this function should never be called if it can't start, but because it does checks to see if they can and could fail, I think that should be captured in the signature.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’ve renamed the DataBrokerProtectionQueueManager
methods in this commit. Note that I have also renamed the QueueManagerMode
cases.
mode = .manual | ||
|
||
// New Manual scans ALWAYS interrupt (i.e cancel) ANY current Manual/Scheduled scans | ||
operationQueue.cancelAllOperations() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd maybe consider making an explicit tear down function, even if it only contains this one line for now, or maybe a single function that handles state transitions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also worth noting this will still have the completion/barrier block bug, where if we interrupt a state, the completion (and anything else in the barrier block) won't be called.
|
||
func startManualScans(showWebView: Bool, operationDependencies: OperationDependencies, completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) { | ||
|
||
guard mode.canInterrupt(forNewMode: .manual) else { return } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mentioned it but recording for prosperity, if we decide not to interrupt, we should call the completion of the function that isn't going to execute (probably with a new error type?)
} | ||
} | ||
|
||
func runAllOptOutOperations(showWebView: Bool, operationDependencies: OperationDependencies, completion: ((DataBrokerProtectionSchedulerErrorCollection?) -> Void)?) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can get rid of some of these, although need to check which ones.
You mentioned it, but recording for prosperity, we should rename them too, since they're not so clear
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’ve removed the unused runAllOperations
method - See this commit
} catch { | ||
os_log("DataBrokerProtectionProcessor error: runOperations, error: %{public}@", log: .error, error.localizedDescription) | ||
operationQueue.addBarrierBlock { | ||
completion(DataBrokerProtectionSchedulerErrorCollection(oneTimeError: error)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hold over from before, but it seems weird and wrong that we don't call the completion immediately if there's an error. So if there's already things on the queue unrelated to this set of scans, it won't run for ages.
(with the current design I don't think there's a case where that's ever true, but no reason to encourage it).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean here it should call completion directly instead of adding the barrierBlock?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, or if not we should record that and make it clear it's deliberate
pixelHandler: pixelHandler) | ||
|
||
var brokerUpdater: DataBrokerProtectionBrokerUpdater? | ||
if let vault = try? DataBrokerProtectionSecureVaultFactory.makeVault(reporter: nil) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's tangental and out of scope, but I don't think we should ever be making the vault directly, and should be striving to use a single DB abstraction (Database)
|
||
typealias OperationType = DataBrokerOperationsCollection.OperationType | ||
|
||
protocol OperationDependencies { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is a big improvement, although I personally don't have any great ideas on what we should be doing with our dependancies in DBP more broadly, so if you have any ideas there it would be good.
XCTAssertTrue(result) | ||
} | ||
|
||
// TODO: More tests to be added as we define expected interruption behaviorgst |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see the TODO here, just adding the suggestion that the most important thing to add here is the case where it's manual scan interrupting manual scan since it's the "edge case" of all other cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @Bunn, I’ve added a test for this scenario in this commit.
…, `IPCServerInterface`, and `XPCServerInterface` interfaces. Remove related Pixel.
…Mode` cases for consistency and clarity
FYI @THISISDINOSAUR and @Bunn - I’m not going to continue any development here. I’ll instead work on new branches to enable opening focused PRs to a feature branch. However, I’ll keep this open for the moment for reference. |
Task/Issue URL:
Tech Design URL:
CC:
Description:
This PR is a proof-of-concept. It demonstrates how we can make our processor logic more testable. If the proof-of-concept is satisfactory, and we get consensus on the approach, we can use this POC as the basis for a final implementation.
The following changes are included:
DataBrokerOperationsCollectionBuilder
DataBrokerProtectionQueueManager
, a refactoring of the currentDataBrokerProtectionProcessor
type, which enables testing of it’s operation queue stateQueueManagerMode
, which captures thestate
of the queue managerDataBrokerProtectionQueueManager
, which can be mockedDataBrokerProtectionQueueManager
DataBrokerProtectionQueueManager
andQueueManagerMode
, and related mocksSteps to test this PR:
1.
—
Internal references:
Pull Request Review Checklist
Software Engineering Expectations
Technical Design Template
Pull Request Documentation