Ejemplo n.º 1
0
        /// <summary>
        /// Creates a plugin from the discovered plugin.
        /// We firstly check the cache for the operation claims for the given request key.
        /// If there is a valid cache entry, and it does contain the requested operation claim, then we start the plugin, and if need be update the cache value itself.
        /// If there is a valid cache entry, and it does NOT contain the requested operation claim, then we return a null.
        /// If there is no valid cache entry or an invalid one, we start the plugin as normally, return an active plugin even if the requested claim is not available, and write a cache entry.
        /// </summary>
        /// <param name="result">plugin discovery result</param>
        /// <param name="requestedOperationClaim">The requested operation claim</param>
        /// <param name="requestKey">plugin request key</param>
        /// <param name="packageSourceRepository">package source repository</param>
        /// <param name="serviceIndex">service index</param>
        /// <param name="cancellationToken">cancellation token</param>
        /// <returns>A plugin creation result, null if the requested plugin cannot handle the given operation claim</returns>
        private async Task <Tuple <bool, PluginCreationResult> > TryCreatePluginAsync(
            PluginDiscoveryResult result,
            OperationClaim requestedOperationClaim,
            PluginRequestKey requestKey,
            string packageSourceRepository,
            JObject serviceIndex,
            CancellationToken cancellationToken)
        {
            PluginCreationResult pluginCreationResult = null;
            var cacheEntry = new PluginCacheEntry(_pluginsCacheDirectory.Value, result.PluginFile.Path, requestKey.PackageSourceRepository);

            return(await ConcurrencyUtilities.ExecuteWithFileLockedAsync(
                       cacheEntry.CacheFileName,
                       action : async lockedToken =>
            {
                if (cacheEntry.OperationClaims == null || cacheEntry.OperationClaims.Contains(requestedOperationClaim))
                {
                    if (result.PluginFile.State.Value == PluginFileState.Valid)
                    {
                        var plugin = await _pluginFactory.GetOrCreateAsync(
                            result.PluginFile.Path,
                            PluginConstants.PluginArguments,
                            new RequestHandlers(),
                            _connectionOptions,
                            cancellationToken);

                        var utilities = await PerformOneTimePluginInitializationAsync(plugin, cancellationToken);

                        // We still make the GetOperationClaims call even if we have the operation claims cached. This is a way to self-update the cache.
                        var operationClaims = await _pluginOperationClaims.GetOrAdd(
                            requestKey,
                            key => new Lazy <Task <IReadOnlyList <OperationClaim> > >(() =>
                                                                                      GetPluginOperationClaimsAsync(
                                                                                          plugin,
                                                                                          packageSourceRepository,
                                                                                          serviceIndex,
                                                                                          cancellationToken))).Value;

                        if (!EqualityUtility.SequenceEqualWithNullCheck(operationClaims, cacheEntry.OperationClaims))
                        {
                            cacheEntry.OperationClaims = operationClaims;
                            await cacheEntry.UpdateCacheFileAsync();
                        }

                        pluginCreationResult = new PluginCreationResult(
                            plugin,
                            utilities.Value,
                            operationClaims);
                    }
                    else
                    {
                        pluginCreationResult = new PluginCreationResult(result.Message);
                    }
                }
                return new Tuple <bool, PluginCreationResult>(pluginCreationResult != null, pluginCreationResult);
            },
                       token : cancellationToken
                       ));
        }
 public void PluginCacheEntry_DoesNotThrowWithNoFile()
 {
     using (var testDirectory = TestDirectory.Create())
     {
         var entry = new PluginCacheEntry(testDirectory.Path, "a", "b");
         entry.LoadFromFile();
         Assert.Null(entry.OperationClaims);
     }
 }
Ejemplo n.º 3
0
        public void PluginCacheEntry_UsesShorterPaths()
        {
            using (var testDirectory = TestDirectory.Create())
            {
                var pluginPath = @"C:\Users\Roki2\.nuget\plugins\netfx\CredentialProvider.Microsoft\CredentialProvider.Microsoft.exe";
                var url        = @"https:\\nugetsspecialfeed.pkgs.visualstudio.com\packaging\ea8caa50-9cf8-4ed7-b410-5bca3b71ec1c\nuget\v3\index.json";

                var entry = new PluginCacheEntry(testDirectory.Path, pluginPath, url);
                entry.LoadFromFile();

                Assert.Equal(86, entry.CacheFileName.Length - testDirectory.Path.Length);
                // This makes it about as long as http cache which is more important.
                // The http cache is 40 + 1 + [1,32] + packageName
                Assert.True(200 > entry.CacheFileName.Length, "The cache file should be short");
            }
        }
        public async Task PluginCacheEntry_DoesNotDeleteAnOpenedFile()
        {
            var list = new List <OperationClaim>()
            {
                OperationClaim.Authentication
            };

            using (var testDirectory = TestDirectory.Create())
            {
                var entry = new PluginCacheEntry(testDirectory.Path, "a", "b");
                entry.LoadFromFile();
                entry.OperationClaims = list;
                await entry.UpdateCacheFileAsync();

                var CacheFileName = Path.Combine(
                    Path.Combine(testDirectory.Path, CachingUtility.RemoveInvalidFileNameChars(CachingUtility.ComputeHash("a", false))),
                    CachingUtility.RemoveInvalidFileNameChars(CachingUtility.ComputeHash("b", false)) + ".dat");

                Assert.True(File.Exists(CacheFileName));

                using (var fileStream = new FileStream(
                           CacheFileName,
                           FileMode.Open,
                           FileAccess.ReadWrite,
                           FileShare.None,
                           CachingUtility.BufferSize,
                           useAsync: true))
                {
                    list.Add(OperationClaim.DownloadPackage);
                    entry.OperationClaims = list;
                    await entry.UpdateCacheFileAsync(); // this should not update
                }

                entry.LoadFromFile();
                Assert.True(EqualityUtility.SequenceEqualWithNullCheck(entry.OperationClaims, new List <OperationClaim>()
                {
                    OperationClaim.Authentication
                }));
            }
        }
        public async Task PluginCacheEntry_RoundTripsValuesAsync(string[] values)
        {
            var list = new List <OperationClaim>();

            foreach (var val in values)
            {
                Enum.TryParse(val, out OperationClaim result);
                list.Add(result);
            }

            using (var testDirectory = TestDirectory.Create())
            {
                var entry = new PluginCacheEntry(testDirectory.Path, "a", "b");
                entry.LoadFromFile();
                entry.OperationClaims = list;
                await entry.UpdateCacheFileAsync();

                var newEntry = new PluginCacheEntry(testDirectory.Path, "a", "b");
                newEntry.LoadFromFile();

                Assert.True(EqualityUtility.SequenceEqualWithNullCheck(entry.OperationClaims, newEntry.OperationClaims));
            }
        }
Ejemplo n.º 6
0
            internal PluginManagerTest(
                string pluginFilePath,
                PluginFileState pluginFileState,
                IReadOnlyList <OperationClaim> operationClaims,
                Mock <IEnvironmentVariableReader> mockEnvironmentVariableReader = null)
            {
                _testDirectory = TestDirectory.Create();

                if (mockEnvironmentVariableReader != null)
                {
                    _reader = mockEnvironmentVariableReader;
                }
                else
                {
                    _reader = new Mock <IEnvironmentVariableReader>(MockBehavior.Strict);

                    _reader.Setup(x => x.GetEnvironmentVariable(
                                      It.Is <string>(value => value == EnvironmentVariableConstants.PluginPaths)))
                    .Returns(pluginFilePath);
                    _reader.Setup(x => x.GetEnvironmentVariable(
                                      It.Is <string>(value => value == EnvironmentVariableConstants.DesktopPluginPaths)))
                    .Returns((string)null);
                    _reader.Setup(x => x.GetEnvironmentVariable(
                                      It.Is <string>(value => value == EnvironmentVariableConstants.CorePluginPaths)))
                    .Returns((string)null);
                    _reader.Setup(x => x.GetEnvironmentVariable(
                                      It.Is <string>(value => value == EnvironmentVariableConstants.RequestTimeout)))
                    .Returns("RequestTimeout");
                    _reader.Setup(x => x.GetEnvironmentVariable(
                                      It.Is <string>(value => value == EnvironmentVariableConstants.IdleTimeout)))
                    .Returns("IdleTimeout");
                    _reader.Setup(x => x.GetEnvironmentVariable(
                                      It.Is <string>(value => value == EnvironmentVariableConstants.HandshakeTimeout)))
                    .Returns("HandshakeTimeout");
                }

                _pluginDiscoverer = new Mock <IPluginDiscoverer>(MockBehavior.Strict);

                _pluginDiscoverer.Setup(x => x.Dispose());
                _pluginDiscoverer.Setup(x => x.DiscoverAsync(It.IsAny <CancellationToken>()))
                .ReturnsAsync(new[]
                {
                    new PluginDiscoveryResult(new PluginFile(pluginFilePath, new Lazy <PluginFileState>(() => pluginFileState)))
                });

                _connection = new Mock <IConnection>(MockBehavior.Strict);

                _connection.Setup(x => x.Dispose());
                _connection.SetupGet(x => x.Options)
                .Returns(ConnectionOptions.CreateDefault());

                _connection.SetupGet(x => x.ProtocolVersion)
                .Returns(ProtocolConstants.CurrentVersion);

                _connection.Setup(x => x.SendRequestAndReceiveResponseAsync <MonitorNuGetProcessExitRequest, MonitorNuGetProcessExitResponse>(
                                      It.Is <MessageMethod>(m => m == MessageMethod.MonitorNuGetProcessExit),
                                      It.IsNotNull <MonitorNuGetProcessExitRequest>(),
                                      It.IsAny <CancellationToken>()))
                .ReturnsAsync(new MonitorNuGetProcessExitResponse(MessageResponseCode.Success));

                _connection.Setup(x => x.SendRequestAndReceiveResponseAsync <InitializeRequest, InitializeResponse>(
                                      It.Is <MessageMethod>(m => m == MessageMethod.Initialize),
                                      It.IsNotNull <InitializeRequest>(),
                                      It.IsAny <CancellationToken>()))
                .ReturnsAsync(new InitializeResponse(MessageResponseCode.Success));

                _connection.Setup(x => x.SendRequestAndReceiveResponseAsync <GetOperationClaimsRequest, GetOperationClaimsResponse>(
                                      It.Is <MessageMethod>(m => m == MessageMethod.GetOperationClaims),
                                      It.Is <GetOperationClaimsRequest>(g => g.PackageSourceRepository == null),
                                      It.IsAny <CancellationToken>()))
                .ReturnsAsync(new GetOperationClaimsResponse(operationClaims));

                _plugin = new Mock <IPlugin>(MockBehavior.Strict);

                _plugin.Setup(x => x.Dispose());
                _plugin.SetupGet(x => x.Connection)
                .Returns(_connection.Object);
                _plugin.SetupGet(x => x.Id)
                .Returns("id");

                _factory = new Mock <IPluginFactory>(MockBehavior.Strict);

                _factory.Setup(x => x.Dispose());
                _factory.Setup(x => x.GetOrCreateAsync(
                                   It.Is <string>(p => p == pluginFilePath),
                                   It.IsNotNull <IEnumerable <string> >(),
                                   It.IsNotNull <IRequestHandlers>(),
                                   It.IsNotNull <ConnectionOptions>(),
                                   It.IsAny <CancellationToken>()))
                .ReturnsAsync(_plugin.Object);

                PluginManager = new PluginManager(
                    _reader.Object,
                    new Lazy <IPluginDiscoverer>(() => _pluginDiscoverer.Object),
                    (TimeSpan idleTimeout) => _factory.Object,
                    new Lazy <string>(() => _testDirectory.Path));

                PluginCacheEntry = new PluginCacheEntry(_testDirectory.Path, pluginFilePath, requestKey: "Source-Agnostic");
                Plugin           = _plugin.Object;
            }