예제 #1
0
        [Ignore] /* Some unknown failure reason at the moment, will need to investigate */
        public void UpdateLocalAsyncWithFailedLFSFetch()
        {
            // Setup
            var control = "test";
            var repo    = Substitute.For <ILocalRepository>();
            var t       = new GitContext(m_config, m_local, m_remote, m_git, m_lfs);

            // The first time the git fetch is called it will pretend success
            m_git.FetchAsync(repo).Returns(x => Task.Run(() => control));
            // but the subsequent call to LFS fetch will fail
            m_lfs.FetchAsync(repo).Returns(x => Task.Run(() => { throw new Exception("test"); }));
            // Which should cause the git clone action
            m_git.CloneAsync(repo).Returns(x => Task.Run(() => control));
            // Followed by a LFS fetch again
            //m_lfs.FetchAsync(repo).Returns(x => Task.Run(() => control));
            m_lfs.FetchAsync(repo).Returns(x => Task.Run(() => control));
            // Act
            var output = t.UpdateLocalAsync(repo).Result;

            // Assert
            Assert.AreEqual(control, output);
            m_git.Received(1).FetchAsync(repo).Wait();
            m_git.Received(1).CloneAsync(repo).Wait();
            m_lfs.Received(2).FetchAsync(repo).Wait();
        } /* End of Function - UpdateLocalAsyncWithFailedLFSFetch */
예제 #2
0
        public void UpdateLocalAsync()
        {
            // Setup
            var control = "test";
            var repo    = Substitute.For <ILocalRepository>();
            var t       = new GitContext(m_config, m_local, m_remote, m_git, m_lfs);

            m_git.FetchAsync(repo).Returns(x => Task.Run(() => control));
            m_lfs.FetchAsync(repo).Returns(x => Task.Run(() => "foobar"));
            // Act
            var output = t.UpdateLocalAsync(repo).Result;

            // Assert
            Assert.AreEqual(control, output);
            m_git.Received(1).FetchAsync(repo).Wait();
            m_lfs.Received(1).FetchAsync(repo).Wait();
        } /* End of Function - UpdateLocalAsync */
예제 #3
0
        public void UpdateLocalAsyncWithFailedGitFetch()
        {
            // Setup
            var control = "test";
            var repo    = Substitute.For <ILocalRepository>();
            var t       = new GitContext(m_config, m_local, m_remote, m_git, m_lfs);

            // The very first call to git fetch will throw
            m_git.FetchAsync(repo).Returns(x => Task.Run(() => { throw new Exception("test"); }));
            // Which should cause a clone to happen instead
            m_git.CloneAsync(repo).Returns(x => Task.Run(() => control));
            // Act
            var output = t.UpdateLocalAsync(repo).Result;

            // Assert
            Assert.AreEqual(control, output);
            m_git.Received(1).FetchAsync(repo).Wait();
            m_git.Received(1).CloneAsync(repo).Wait();
            m_lfs.Received(1).FetchAsync(repo).Wait();
        } /* End of Function - UpdateLocalAsyncWithFailedGitFetch */
        } /* End of Function - ReaderWriterLockFilterAsyncAttribute */

        /************************ Methods ****************************************/
        /*----------------------- OnResourceExecutionAsync ----------------------*/
        /// <summary>
        /// Wraps the execution with a lock, if out of date will get a writer lock
        /// otherwise will continue through as a reader
        /// </summary>
        /// <param name="context"></param>
        /// <param name="next"></param>
        /// <remarks>
        /// This method does not use the async keyword, due to `await` to possibly
        /// change the thread we are executing on, causing problems with the locks.
        /// </remarks>
        public Task OnResourceExecutionAsync(
            ResourceExecutingContext context,
            ResourceExecutionDelegate next)
        {
            if (null == context)
            {
                throw new ArgumentNullException(
                          nameof(context), "A valid context must be provided");
            }

            if (null == next)
            {
                throw new ArgumentNullException(
                          nameof(next), "A valid execution delegate must be provided");
            }

            return(Task.Factory.StartNew(() =>
            {
                Logger.LogTrace("Enter main execution task");
                // Grab the timeout value from configuration
                var timeout = GetWaitTimeSpan();
                Logger.LogInformation($"Got a timeout from configuration: {timeout}");
                Logger.LogInformation($"  In milliseconds: {timeout.TotalMilliseconds}");
                // Get a lock object associated with the resource key
                var lockObj = Manager.GetFor(GetResourceKey(context));

                string auth = null;
                // Will look in the headers for an "Authentication" record
                var headers = context.HttpContext.Request.Headers;
                // If so, then we will get the value to use (assuming the first is
                // good enough, since there should just be one)
                if (headers.ContainsKey("Authorization"))
                {
                    auth = headers["Authorization"].First();
                }

                var repo = GitContext.RemoteFactory.Build(context.RouteData.Values["destinationServer"].ToString(),
                                                          context.RouteData.Values["repositoryOwner"].ToString(),
                                                          context.RouteData.Values["repository"].ToString(),
                                                          auth);
                var local = GitContext.LocalFactory.Build(repo, Configuration);

                Logger.LogInformation("Grabbing reader lock");
                lockObj.AcquireReaderLock(timeout);
                if (!IsRepositoryUpToDate(local))
                {
                    Logger.LogInformation("Repository out of date, asking for writer lock");
                    //lockObj.AcquireWriterLock(timeout);
                    lockObj.UpgradeToWriterLock(timeout);
                } // end of if - out-of-date

                try
                {
                    // Check to see if we are out of date, if we are then
                    // upgrade to writer, to update our local values
                    if (lockObj.IsWriterLockHeld)
                    {
                        // If still out of date, then we will update the local one,
                        // because we are the instance stuck with the work
                        if (!IsRepositoryUpToDate(local))
                        {
                            Logger.LogInformation("We are responsible for updating the local repository");
                            GitContext.UpdateLocalAsync(local).Wait();
                            Logger.LogInformation("Local repository updated!");
                        }
                        lockObj.DowngradeFromWriterLock();
                    } // end of if - repository is up-to-date

                    Logger.LogInformation("Calling through to the next step in the pipeline");
                    // Allow the rest of the pipeline to continue
                    next().Wait();

                    Logger.LogInformation("Next action has finished, continue to release locks");
                } // end of try - to execute the job
                finally
                {
                    // If we were holding the writer lock, release it
                    // first
                    if (lockObj.IsWriterLockHeld)
                    {
                        Logger.LogInformation("Releasing the writer lock");
                        lockObj.ReleaseWriterLock();
                        Logger.LogInformation("Writer lock released");
                    } // end of if - writer lock is held
                    else
                    {
                        Logger.LogInformation("Releasing the reader lock");
                        lockObj.ReleaseReaderLock();
                    } // end of else - reader lock
                }     // end of finally
                lockObj = null;
                Logger.LogTrace("Exit main execution task");
            })); // end of task
        } /* End of Function - OnResourceExecutionAsync */