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

Package B should not overwrite CustomNodes defined in Package A #9841

Merged
merged 8 commits into from
Jul 16, 2019

Conversation

mjkkirschner
Copy link
Member

@mjkkirschner mjkkirschner commented Jul 11, 2019

Purpose

Updated:

After going back and forth with this for a few days my opinion is that we should move very slowly with this change because the customNodeManager and package loading logic is quite fragile and has many cases. Some of which are not well defined today. I think before we can change these we need to define them and the expected behavior.

Having said that here is what I'm proposing and what I have found.

I propose that at this time we only change one loading behavior to address the initial bug we identified using the WorkspaceDependencyViewer that one node could belong to two packages.

After this PR:

  1. CustomNodes cannot be redefined by a completely separate package.
    If you try to load two conflicting packages you see this message(added by @aparajit-pratap ):
 {package2} cannot be loaded. 
        ///Installing it will conflict with one or more node definitions that already exist in {package1}, which is currently loaded. 
        ///To install {package2}, Dynamo needs to first uninstall {package1}. 
        ///Restart Dynamo to complete the uninstall..
  1. this means they CAN be redefined by other versions of the same package. This is to support versioning publishing workflows. Until we are ready to refactor and study these cases and the inconsistency that exists today I have added a notification which is raised if an existing definition or version is being overridden by a package.
Attempting to load customNode EvenOdd, loaded by package EvenOdd, 
Version=1.0.0, but A previous definition named MyNewEvenOdd exists with no associated package. 
The new customNode definition has been loaded,
 but Dynamo may in an unstable state, please avoid loading multiple custom nodes with the id 3f19c484-d3f3-49ba-88c2-6c386a41f6ac. 

These are the only cases which are changed, and the only one that prevents loading is number 1. - I think this has low risk since most behaviors are unchanged, and provides some more information to help users understand what is being overwritten and by what.

These are the cases I was able to write automated tests for:

  • CustomNode is loose - edited by a user, and resaved
  • CustomNode is from a package and edited by a user.
  • Two packages contain the same custom node definition, a node is placed from package 1, and package 2 attempts to load - conflicting package2 does not load.
  • Placing a custom node from a package retains the packageInfo on the CustomNodeInfo

These are the cases I could not write tests for, but work in Dynamo:

  • Custom node with conflicting ID is in definitions folder, Package containing same ID is loaded, package overwrites customNode and logs a warning.
  • The reverse of the above - loading the package first and then creating the customNode -

These are cases that are not well defined or have surprising behavior that I am hesitant to change.

  • Publishing a new customNode to a package does not actually load the customNodes again, but it does move the custom node to a new location - the package is loaded, but contains no customNodes - this is existing behavior.
  • Publishing a version does reload the custom nodes.

PackageInfo added to CustomNodeInfo

To handle these cases the PackageInfo class was made public and added to the CusotmNodeInfo class as a property - this property is valid if the customNode was requested to be loaded as a consequence of some package being loaded.

I found out that IsPackageMember was never consistently set on the CustomNodeInfo - ⚠️ I believe this is the information we absolutely must know to address case 1. (packages overwriting other packages) - To address this when CustomNodeInfo is set the CustomNodeManager requests the packageManager return the owningPackage of the customNode if it exists, this is done with a dictionary lookup, so it is fast.

Next we check the updated info is owned by a package, if it is, we check if the same package added the existing customNodeInfo - if so, we update the info. If the existing Info has no package - we log a notification (the one above in case 2), and still load the package.

The only case that throws, is case 1. Two different packages (tested by Name only) are trying to redefine the same info tested by Guid.

PR Also does the following:

  • removes testMode added in previous PR
  • simplifies message when trying to install a package that is already installed and requires restart.
  • removes failure category from LibraryJSCustomNodetest.
  • adds some Failing tests, with the category TechDebt that I hope we can address as we define the expected behavior of these other cases and eventually refactor CustomNodeManager / PackageLoader.

Declarations

Check these if you believe they are true

  • The code base is in a better state after this PR
  • Is documented according to the standards
  • The level of testing this PR includes is appropriate
  • User facing strings, if any, are extracted into *.resx files
  • All tests pass using the self-service CI.
  • Snapshot of UI changes, if any.
  • Changes to the API follow Semantic Versioning, and are documented in the API Changes document.

Reviewers

(FILL ME IN) Reviewer 1 (If possible, assign the Reviewer for the PR)

(FILL ME IN, optional) Any additional notes to reviewers or testers.

FYIs

@aparajit-pratap @scottmitchell @QilongTang

fix tests
pass PackageInfo around
add PackageInfo to customNodeInfo class
use it to throw exceptions
change message when installing package that already is installed.
@mjkkirschner mjkkirschner changed the title CustomNodes should be allowed to be redefined in certain cases. [WIP]CustomNodes should be allowed to be redefined in certain cases. Jul 11, 2019
@@ -6,7 +6,7 @@ namespace Dynamo.Graph.Workspaces
/// <summary>
/// Class containing info about a package
/// </summary>
internal class PackageInfo
public class PackageInfo
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good, we still end up making it public. Would you check if there is any internal available code we need to remove?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will do.

public IEnumerable<CustomNodeInfo> AddUninitializedCustomNodesInPath(string path, bool isTestMode, PackageInfo packageInfo)
{
var result = new List<CustomNodeInfo>();
foreach (var info in ScanNodeHeadersInDirectory(path, isTestMode))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without checking the function ScanNodeHeadersInDirectory can you tell us a bit why testMode is needed here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so because this function results in loading something from disk, its needed to be passed down to the xml and json deserialization methods:

https://github.com/DynamoDS/Dynamo/blob/master/src/DynamoCore/Core/CustomNodeManager.cs#L601

eventually... it's used to fail tests, which is a good thing (instead of logging the exceptions like we do at runtime)

@aparajit-pratap
Copy link
Contributor

@mjkkirschner there are few other places where you need to make changes to account for the isTestMode removal - mainly in the tests. Please refer to commit: 1c38933

@aparajit-pratap
Copy link
Contributor

Aside from the comments above, looks good. Thanks @mjkkirschner

@QilongTang
Copy link
Contributor

Some comments there, with Unit tests should look good

@mjkkirschner
Copy link
Member Author

mjkkirschner commented Jul 13, 2019 via email

@mjkkirschner mjkkirschner added the DNM Do not merge. For PRs. label Jul 14, 2019
…Info objects

use correct customNodeLoading method from Package object when publishing a package
update test
Assert.AreEqual(2, nodeInstance.OutPorts.Count());
Assert.AreEqual("anewoutput", nodeInstance.OutPorts[1].Name);

}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice test 👍

@mjkkirschner
Copy link
Member Author

@aparajit-pratap @QilongTang - you may want to hang on before reviewing this again - I will redo my PR description as my thinking on this has changed a bit.

@aparajit-pratap
Copy link
Contributor

@mjkkirschner given the new findings from your testing and the need to add these new events, I feel that adding the PackageInfo property to CustomNodeInfo has added more complexity. I'm trying to understand if it was really worth doing this and what are the advantages other than package equality is done better using PackageInfo objects rather than CustomNodeInfo.Path strings.

@mjkkirschner
Copy link
Member Author

@aparajit-pratap - yep we can discuss more tomorrow, I do not think the path information alone gives us enough to make the correct determination, some examples:

  • if I work on a package and publish a version we can't identify this case - (granted I'm not raising any errors now for this case) - but it will not be easily possible to identify it from paths.
  • I am working on a new loose custom node, then I publish it (potentially it gets reloaded from a new path) -
  • The packageMember flag is incorrectly set as soon as you place a node - so the check in your followup PR will not work after interacting with Dynamo, it will only work on first load.

Alot of these cases are tricky no matter if we use paths or packageInfo - the crux being that the PackageMember flag was never set consistently,

tldr;
No matter if we use paths or packageInfo - we will have to do extra work to keep the flag indicating package membership in sync - see the latest commits using RequestCustomNodeOwner - I don't think the packageInfo was the complicated part, it's just that we don't have good information on if a customNode belongs to a package today, and to identify the case we are trying to solve, we need to know this accurately.

…m node

address some review comments
add some tech debt test cases
@mjkkirschner mjkkirschner changed the title [WIP]CustomNodes should be allowed to be redefined in certain cases. PTAL CustomNodes should be allowed to be redefined in certain cases. Jul 15, 2019
@mjkkirschner mjkkirschner changed the title PTAL CustomNodes should be allowed to be redefined in certain cases. CustomNodes should be allowed to be redefined in certain cases. Jul 15, 2019
@mjkkirschner mjkkirschner changed the title CustomNodes should be allowed to be redefined in certain cases. Package B should not overwrite CustomNodes defined in Package A Jul 15, 2019
@mjkkirschner mjkkirschner removed the DNM Do not merge. For PRs. label Jul 15, 2019
@mjkkirschner mjkkirschner added PTAL Please Take A Look 👀 and removed WIP labels Jul 15, 2019
if (newInfo.PackageInfo.Name != info.PackageInfo.Name)

//only try to compare package info if both customNodeInfos have package info.
if(info.IsPackageMember && info.PackageInfo != null)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't one being true mean the other is true - if IsPackageMember is true, doesn't it imply that PackageInfo is non-null or is this double check just to be safe?

Copy link
Member Author

@mjkkirschner mjkkirschner Jul 15, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, it's just a double check, the second check should always be true if the first is true - but I wanted to verify.


Assert.AreEqual(new PackageInfo("PublishingACustomNodeSetsPackageInfoCorrectly", new Version(0,0,1))
,GetModel().CustomNodeManager.NodeInfos[cnworkspace.CustomNodeId].PackageInfo);
Assert.IsFalse(GetModel().CustomNodeManager.NodeInfos[cnworkspace.CustomNodeId].IsPackageMember);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this not expected to be true?

Copy link
Member Author

@mjkkirschner mjkkirschner Jul 15, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is currently false, because the new package does not actually get loaded. - It just gets added to the list of loaded packages... not exactly the same thing. Thats why this one is tech debt, my expectations were not what I found.

this.CurrentDynamoModel.CurrentWorkspace.AddAndRegisterNode(customNodeInstance);

//load again.
loader.LoadPackages(new Package[] { package1, package2 });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you loading the packages again here? One of them is already loaded so it's not going to load again, is it? The following assertions are going to work even without this LoadPackages call again, won't they?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to try loading package2 again - after the customNodeInstance is placed - because this action resets the customNodeInfo to not include the package info - so I want to verify that loading package2 (which was not loaded the first time) - is still not loaded even after creating an instance of this custom node.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could be more explicit and not try to load package1 again for clarity.

@aparajit-pratap
Copy link
Contributor

LGTM!

@mjkkirschner mjkkirschner merged commit 8d47577 into DynamoDS:master Jul 16, 2019
mjkkirschner added a commit that referenced this pull request Aug 3, 2019
* remove testMode
fix tests
pass PackageInfo around
add PackageInfo to customNodeInfo class
use it to throw exceptions
change message when installing package that already is installed.

* add new tests
finish removing test mode
add new package

* update test

* update test and package json

* try using package manger to keep packageInfo up to date on customNodeInfo objects
use correct customNodeLoading method from Package object when publishing a package
update test

* add logging for different case to setInfo

* update message for feedback when package overwrites non package custom node
address some review comments
add some tech debt test cases
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
PTAL Please Take A Look 👀
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants