public void AddProject_RemoveProject_Clear_TriggerNoEvent_WithEventHandler()
        {
            // Arrange
            var target       = new ProjectSystemCache();
            var projectNames = new ProjectNames(
                fullName: @"C:\src\project\project.csproj",
                uniqueName: @"folder\project",
                shortName: "project",
                customUniqueName: @"folder\project");
            var projectNamesFromFullPath = ProjectNames.FromFullProjectPath(@"C:\src\project\project.csproj");
            var projectRestoreInfo       = new DependencyGraphSpec();
            var eventCount = 0;

            target.CacheUpdated += delegate(object sender, NuGetEventArgs <string> e)
            {
                if (target.TestResetDirtyFlag())
                {
                    eventCount++;
                }
            };

            // Act
            target.AddProject(projectNames, vsProjectAdapter: null, nuGetProject: null);
            target.RemoveProject(projectNames.FullName);
            target.Clear();

            // Assert
            Assert.Equal(target.IsCacheDirty, 0);
            Assert.Equal(eventCount, 0);
        }
        public void AddProjectRestoreInfo_TriggersNoEvent_NoEventHandler()
        {
            // Arrange
            var target       = new ProjectSystemCache();
            var projectNames = new ProjectNames(
                fullName: @"C:\src\project\project.csproj",
                uniqueName: @"folder\project",
                shortName: "project",
                customUniqueName: @"folder\project");
            var projectNamesFromFullPath = ProjectNames.FromFullProjectPath(@"C:\src\project\project.csproj");
            var projectRestoreInfo       = new DependencyGraphSpec();

            // Act
            target.AddProjectRestoreInfo(projectNamesFromFullPath, projectRestoreInfo);
            target.AddProject(projectNames, vsProjectAdapter: null, nuGetProject: null);

            // Assert
            DependencyGraphSpec actual;
            ProjectNames        names;
            var getPackageSpecSuccess = target.TryGetProjectRestoreInfo(projectNames.FullName, out actual);
            var getProjectNameSuccess = target.TryGetProjectNames(projectNames.UniqueName, out names);

            Assert.True(getPackageSpecSuccess);
            Assert.True(getProjectNameSuccess);
            Assert.Same(projectRestoreInfo, actual);
            Assert.Equal(@"folder\project", names.CustomUniqueName);
            // Cache remains clean since no one is listening to the cache events
            Assert.Equal(target.IsCacheDirty, 0);
        }
        /// <summary>
        /// This is where the nominate calls for the IVs1 and IVS3 APIs combine. The reason for this method is to avoid duplication and potential issues
        /// The issue with this method is that it has some weird custom logging to ensure backward compatibility. It's on the implementer to ensure these calls are correct.
        /// <param name="projectUniqueName">projectUniqueName</param>
        /// <param name="projectRestoreInfo">projectRestoreInfo. Can be null</param>
        /// <param name="projectRestoreInfo2">proectRestoreInfo2. Can be null</param>
        /// <param name="token"></param>
        /// <remarks>Exactly one of projectRestoreInfos has to null.</remarks>
        /// <returns>The task that scheduled restore</returns>
        private Task <bool> NominateProjectAsync(string projectUniqueName, IVsProjectRestoreInfo projectRestoreInfo, IVsProjectRestoreInfo2 projectRestoreInfo2, CancellationToken token)
        {
            if (string.IsNullOrEmpty(projectUniqueName))
            {
                throw new ArgumentException(Resources.Argument_Cannot_Be_Null_Or_Empty, nameof(projectUniqueName));
            }

            if (projectRestoreInfo == null && projectRestoreInfo2 == null)
            {
                throw new ArgumentNullException(nameof(projectRestoreInfo));
            }

            if (projectRestoreInfo != null && projectRestoreInfo2 != null)
            {
                throw new ArgumentException($"Internal error: Both {nameof(projectRestoreInfo)} and {nameof(projectRestoreInfo2)} cannot have values. Please file an issue at NuGet/Home if you see this exception.");
            }

            if (projectRestoreInfo != null)
            {
                if (projectRestoreInfo.TargetFrameworks == null)
                {
                    throw new InvalidOperationException("TargetFrameworks cannot be null.");
                }
            }
            else
            {
                if (projectRestoreInfo2.TargetFrameworks == null)
                {
                    throw new InvalidOperationException("TargetFrameworks cannot be null.");
                }
            }

            try
            {
                _logger.LogInformation(
                    $"The nominate API is called for '{projectUniqueName}'.");

                var projectNames = ProjectNames.FromFullProjectPath(projectUniqueName);

                var dgSpec = ToDependencyGraphSpec(projectNames, projectRestoreInfo, projectRestoreInfo2);

                _projectSystemCache.AddProjectRestoreInfo(projectNames, dgSpec);

                // returned task completes when scheduled restore operation completes.
                var restoreTask = _restoreWorker.ScheduleRestoreAsync(
                    SolutionRestoreRequest.OnUpdate(),
                    token);

                return(restoreTask);
            }
            catch (OperationCanceledException)
            {
                throw;
            }
            catch (Exception e)
            {
                _logger.LogError(e.ToString());
                return(Task.FromResult(false));
            }
        }
        public void AddProject_AfterAddProjectRestoreInfo_UpdatesCacheEntry()
        {
            // Arrange
            var target       = new ProjectSystemCache();
            var projectNames = new ProjectNames(
                fullName: @"C:\src\project\project.csproj",
                uniqueName: @"folder\project",
                shortName: "project",
                customUniqueName: @"folder\project");
            var projectNamesFromFullPath = ProjectNames.FromFullProjectPath(@"C:\src\project\project.csproj");
            var projectRestoreInfo       = new DependencyGraphSpec();

            target.AddProjectRestoreInfo(projectNamesFromFullPath, projectRestoreInfo);

            // Act
            target.AddProject(projectNames, vsProjectAdapter: null, nuGetProject: null);

            // Assert
            DependencyGraphSpec actual;
            ProjectNames        names;

            var getPackageSpecSuccess = target.TryGetProjectRestoreInfo(projectNames.FullName, out actual);
            var getProjectNameSuccess = target.TryGetProjectNames(projectNames.UniqueName, out names);

            Assert.True(getPackageSpecSuccess);
            Assert.True(getProjectNameSuccess);
            Assert.Same(projectRestoreInfo, actual);
            Assert.Equal(@"folder\project", names.CustomUniqueName);
        }
        public void AddProjectRestoreInfo_TriggersMultipleEvent_WithEventHandler_WithReset()
        {
            // Arrange
            var target                   = new ProjectSystemCache();
            var projectNames             = GetTestProjectNames();
            var projectNamesFromFullPath = ProjectNames.FromFullProjectPath(projectNames.FullName);
            var projectRestoreInfo       = new DependencyGraphSpec();
            var eventCount               = 0;

            target.CacheUpdated += delegate(object sender, NuGetEventArgs <string> e)
            {
                if (target.TestResetDirtyFlag())
                {
                    eventCount++;
                }
            };

            // Act
            target.AddProjectRestoreInfo(projectNamesFromFullPath, projectRestoreInfo, additionalMessages: null);
            target.AddProjectRestoreInfo(projectNamesFromFullPath, projectRestoreInfo, additionalMessages: null);
            target.AddProjectRestoreInfo(projectNamesFromFullPath, projectRestoreInfo, additionalMessages: null);
            target.AddProjectRestoreInfo(projectNamesFromFullPath, projectRestoreInfo, additionalMessages: null);

            // Assert
            Assert.Equal(target.IsCacheDirty, 0);
            Assert.Equal(eventCount, 4);
        }
        public void AddProjectRestoreInfo_TriggersEvent_WithEventHandler_NoReset()
        {
            // Arrange
            var target                   = new ProjectSystemCache();
            var projectNames             = GetTestProjectNames();
            var projectNamesFromFullPath = ProjectNames.FromFullProjectPath(projectNames.FullName);
            var projectRestoreInfo       = new DependencyGraphSpec();
            var eventCount               = 0;

            target.CacheUpdated += delegate(object sender, NuGetEventArgs <string> e)
            {
                eventCount++;
            };

            // Act
            target.AddProjectRestoreInfo(projectNamesFromFullPath, projectRestoreInfo, additionalMessages: null);
            target.AddProjectRestoreInfo(projectNamesFromFullPath, projectRestoreInfo, additionalMessages: null);
            target.AddProject(projectNames, vsProjectAdapter: null, nuGetProject: null);

            // Assert
            DependencyGraphSpec actual;
            ProjectNames        names;
            var getPackageSpecSuccess = target.TryGetProjectRestoreInfo(projectNames.FullName, out actual, out _);
            var getProjectNameSuccess = target.TryGetProjectNames(projectNames.UniqueName, out names);

            Assert.True(getPackageSpecSuccess);
            Assert.True(getProjectNameSuccess);
            Assert.Same(projectRestoreInfo, actual);
            Assert.Equal(@"folder\project", names.CustomUniqueName);

            // Since no listener resets the dirty flag, the cache remains dirty and only 1 event is raised.
            Assert.Equal(target.IsCacheDirty, 1);
            Assert.Equal(eventCount, 1);
        }
        public void AddProjectRestoreInfo_AfterAddProject_UpdatesCacheEntry()
        {
            // Arrange
            var target                   = new ProjectSystemCache();
            var projectNames             = GetTestProjectNames();
            var projectNamesFromFullPath = ProjectNames.FromFullProjectPath(projectNames.FullName);
            var projectRestoreInfo       = new DependencyGraphSpec();

            target.AddProject(projectNames, vsProjectAdapter: null, nuGetProject: null);

            // Act
            target.AddProjectRestoreInfo(projectNamesFromFullPath, projectRestoreInfo, additionalMessages: null);

            // Assert
            var getPackageSpecSuccess = target.TryGetProjectRestoreInfo(projectNames.FullName, out var actual, out _);
            var getProjectNameFromUniqueNameSuccess = target.TryGetProjectNames(projectNames.UniqueName, out var names1);
            var getProjectNameFromFullNameSuccess   = target.TryGetProjectNames(projectNames.FullName, out var names2);

            Assert.True(getPackageSpecSuccess);
            Assert.True(getProjectNameFromUniqueNameSuccess);
            Assert.True(getProjectNameFromFullNameSuccess);
            Assert.Same(projectRestoreInfo, actual);
            Assert.Equal(@"folder\project", names1.CustomUniqueName);
            Assert.Equal(@"folder\project", names2.CustomUniqueName);
        }
Example #8
0
        public void AddProject_AfterAddProjectRestoreInfoWithProjectId_DoesNotUpdatesCacheEntryProjectId()
        {
            // Arrange
            var target              = new ProjectSystemCache();
            var projectNames        = ProjectNames.FromFullProjectPath(@"C:\src\project\project.csproj");
            var originalProjectSpec = new PackageSpec()
            {
                ProjectId       = Guid.NewGuid().ToString(),
                Name            = projectNames.UniqueName,
                RestoreMetadata = new ProjectRestoreMetadata()
                {
                    ProjectUniqueName = projectNames.UniqueName
                }
            };
            var projectRestoreInfo = new DependencyGraphSpec();
            var nugetProject       = new TestNuGetProject(projectNames.UniqueName, new List <PackageReference>());

            projectRestoreInfo.AddProject(originalProjectSpec);

            target.AddProjectRestoreInfo(projectNames, projectRestoreInfo);

            // Act
            target.AddProject(projectNames, vsProjectAdapter: null, nuGetProject: nugetProject);

            // Assert
            var getPackageSpecSuccess = target.TryGetProjectRestoreInfo(projectNames.FullName, out var actual);

            // Assert
            getPackageSpecSuccess.Should().BeTrue();
            actual.Projects.Count.Should().Be(1);
            actual.Projects.First().ProjectId.Should().Be(originalProjectSpec.ProjectId);
        }
Example #9
0
        public void AddProject_AfterAddProjectRestoreInfoWithNullProject_DoesNotUpdatesCacheEntryProjectId()
        {
            // Arrange
            var target       = new ProjectSystemCache();
            var projectNames = ProjectNames.FromFullProjectPath(@"C:\src\project\project.csproj");
            var projectSpec  = new PackageSpec()
            {
                ProjectId       = string.Empty,
                Name            = projectNames.UniqueName,
                RestoreMetadata = new ProjectRestoreMetadata()
                {
                    ProjectUniqueName = projectNames.UniqueName
                }
            };
            var projectRestoreInfo = new DependencyGraphSpec();

            projectRestoreInfo.AddProject(projectSpec);

            target.AddProjectRestoreInfo(projectNames, projectRestoreInfo);

            // Act
            target.AddProject(projectNames, vsProjectAdapter: null, nuGetProject: null);

            // Assert
            var getPackageSpecSuccess = target.TryGetProjectRestoreInfo(projectNames.FullName, out var actual);

            // Assert
            getPackageSpecSuccess.Should().BeTrue();
            actual.Projects.Count.Should().Be(1);
            actual.Projects.First().ProjectId.Should().Be(string.Empty);
        }
Example #10
0
        public Task <bool> NominateProjectAsync(string projectUniqueName, IVsProjectRestoreInfo projectRestoreInfo, CancellationToken token)
        {
            if (string.IsNullOrEmpty(projectUniqueName))
            {
                throw new ArgumentException(Resources.Argument_Cannot_Be_Null_Or_Empty, nameof(projectUniqueName));
            }

            if (projectRestoreInfo == null)
            {
                throw new ArgumentNullException(nameof(projectRestoreInfo));
            }

            if (projectRestoreInfo.TargetFrameworks == null)
            {
                throw new InvalidOperationException("TargetFrameworks cannot be null.");
            }

            try
            {
                _logger.LogInformation(
                    $"The nominate API is called for '{projectUniqueName}'.");

                var projectNames = ProjectNames.FromFullProjectPath(projectUniqueName);

                var dgSpec = ToDependencyGraphSpec(projectNames, projectRestoreInfo);
#if DEBUG
                DumpProjectRestoreInfo(projectUniqueName, dgSpec);
#endif
                _projectSystemCache.AddProjectRestoreInfo(projectNames, dgSpec);

                // returned task completes when scheduled restore operation completes.
                var restoreTask = _restoreWorker.ScheduleRestoreAsync(
                    SolutionRestoreRequest.OnUpdate(),
                    token);

                return(restoreTask);
            }
            catch (Exception e)
                when(e is InvalidOperationException || e is ArgumentException || e is FormatException)
                {
                    _logger.LogError(e.ToString());
                    return(Task.FromResult(false));
                }
            catch (Exception e)
            {
                _logger.LogError(e.ToString());
                throw;
            }
        }
        public void AddProjectRestoreInfo_TriggersEvent_WithEventHandler_WithReset()
        {
            // Arrange
            var target       = new ProjectSystemCache();
            var projectNames = new ProjectNames(
                fullName: @"C:\src\project\project.csproj",
                uniqueName: @"folder\project",
                shortName: "project",
                customUniqueName: @"folder\project");
            var projectNamesFromFullPath = ProjectNames.FromFullProjectPath(@"C:\src\project\project.csproj");
            var projectRestoreInfo       = new DependencyGraphSpec();
            var eventCount = 0;

            target.CacheUpdated += delegate(object sender, NuGetEventArgs <string> e)
            {
                if (target.TestResetDirtyFlag())
                {
                    eventCount++;
                }
            };

            // Act
            target.AddProjectRestoreInfo(projectNamesFromFullPath, projectRestoreInfo);
            target.AddProject(projectNames, vsProjectAdapter: null, nuGetProject: null);

            // Assert
            DependencyGraphSpec actual;
            ProjectNames        names;
            var getPackageSpecSuccess = target.TryGetProjectRestoreInfo(projectNames.FullName, out actual);
            var getProjectNameSuccess = target.TryGetProjectNames(projectNames.UniqueName, out names);

            Assert.True(getPackageSpecSuccess);
            Assert.True(getProjectNameSuccess);
            Assert.Same(projectRestoreInfo, actual);
            Assert.Equal(@"folder\project", names.CustomUniqueName);
            Assert.Equal(target.IsCacheDirty, 0);
            Assert.Equal(eventCount, 1);
        }
Example #12
0
        /// <summary>
        /// This is where the nominate calls for the IVs1 and IVS3 APIs combine. The reason for this method is to avoid duplication and potential issues
        /// The issue with this method is that it has some weird custom logging to ensure backward compatibility. It's on the implementer to ensure these calls are correct.
        /// <param name="projectUniqueName">projectUniqueName</param>
        /// <param name="projectRestoreInfo">projectRestoreInfo. Can be null</param>
        /// <param name="projectRestoreInfo2">proectRestoreInfo2. Can be null</param>
        /// <param name="token"></param>
        /// <remarks>Exactly one of projectRestoreInfos has to null.</remarks>
        /// <returns>The task that scheduled restore</returns>
        private Task <bool> NominateProjectAsync(string projectUniqueName, IVsProjectRestoreInfo projectRestoreInfo, IVsProjectRestoreInfo2 projectRestoreInfo2, CancellationToken token)
        {
            if (string.IsNullOrEmpty(projectUniqueName))
            {
                throw new ArgumentException(Resources.Argument_Cannot_Be_Null_Or_Empty, nameof(projectUniqueName));
            }

            if (projectRestoreInfo == null && projectRestoreInfo2 == null)
            {
                throw new ArgumentNullException(nameof(projectRestoreInfo));
            }

            if (projectRestoreInfo != null && projectRestoreInfo2 != null)
            {
                throw new ArgumentException($"Internal error: Both {nameof(projectRestoreInfo)} and {nameof(projectRestoreInfo2)} cannot have values. Please file an issue at NuGet/Home if you see this exception.");
            }

            if (projectRestoreInfo != null)
            {
                if (projectRestoreInfo.TargetFrameworks == null)
                {
                    throw new InvalidOperationException("TargetFrameworks cannot be null.");
                }
            }
            else
            {
                if (projectRestoreInfo2.TargetFrameworks == null)
                {
                    throw new InvalidOperationException("TargetFrameworks cannot be null.");
                }
            }

            try
            {
                _logger.LogInformation(
                    $"The nominate API is called for '{projectUniqueName}'.");

                var projectNames = ProjectNames.FromFullProjectPath(projectUniqueName);
                DependencyGraphSpec dgSpec;
                IReadOnlyList <IAssetsLogMessage> nominationErrors = null;
                try
                {
                    dgSpec = ToDependencyGraphSpec(projectNames, projectRestoreInfo, projectRestoreInfo2);
                }
                catch (Exception e)
                {
                    var restoreLogMessage = RestoreLogMessage.CreateError(NuGetLogCode.NU1105, string.Format(Resources.NU1105, projectNames.ShortName, e.Message));
                    restoreLogMessage.LibraryId = projectUniqueName;

                    nominationErrors = new List <IAssetsLogMessage>()
                    {
                        AssetsLogMessage.Create(restoreLogMessage)
                    };

                    var    projectDirectory        = Path.GetDirectoryName(projectUniqueName);
                    string projectIntermediatePath = projectRestoreInfo == null
                        ? projectRestoreInfo2.BaseIntermediatePath
                        : projectRestoreInfo.BaseIntermediatePath;
                    var dgSpecOutputPath = GetProjectOutputPath(projectDirectory, projectIntermediatePath);
                    dgSpec = CreateMinimalDependencyGraphSpec(projectUniqueName, dgSpecOutputPath);
                }

                _projectSystemCache.AddProjectRestoreInfo(projectNames, dgSpec, nominationErrors);

                // returned task completes when scheduled restore operation completes.
                var restoreTask = _restoreWorker.ScheduleRestoreAsync(
                    SolutionRestoreRequest.OnUpdate(),
                    token);

                return(restoreTask);
            }
            catch (OperationCanceledException)
            {
                throw;
            }
            catch (Exception e)
            {
                _logger.LogError(e.ToString());
                TelemetryUtility.EmitException(nameof(VsSolutionRestoreService), nameof(NominateProjectAsync), e);
                return(Task.FromResult(false));
            }
        }