예제 #1
0
        /// <inheritdoc />
        public async Task <IEnumerable <WorkItem> > GetWorkItemsAsync(WorkItemsQuery query, bool expand = false, CancellationToken cancellationToken = default(CancellationToken))
        {
            var queryResult = await ExecuteQueryAsync(query, cancellationToken);

            int[] ids;
            switch (queryResult)
            {
            case FlatWorkItemsQueryResult flat:
                ids = GetWorkitemIdsFromQuery(flat);
                break;

            case HierarchicalWorkItemsQueryResult tree:
                ids = GetWorkitemIdsFromQuery(tree);
                break;

            default:
                throw new NotSupportedException($"Query result is of not supported type.");
            }

            if (!ids.Any())
            {
                return(Enumerable.Empty <WorkItem>());
            }

            if (!expand)
            {
                var columns = queryResult.Columns.Select(c => c.ReferenceName).ToArray();
                return(await GetWorkItemsAsync(ids, fields : columns, cancellationToken : cancellationToken));
            }
            else
            {
                return(await GetWorkItemsAsync(ids, cancellationToken : cancellationToken));
            }
        }
예제 #2
0
        public async Task GetWorkItemsShouldComposeCorrectUrlForFlatQueries()
        {
            var query       = WorkItemsQuery.Get("Dummy query");
            var queryResult = new FlatWorkItemsQueryResult
            {
                Columns   = new[] { new ColumnReference("Id", "System.Id"), new ColumnReference("Title", "System.Title") },
                WorkItems = new[] { new WorkItemReference(2), new WorkItemReference(34), new WorkItemReference(56) }
            };
            var fields    = queryResult.Columns.Select(c => c.ReferenceName);
            var ids       = queryResult.WorkItems.Select(w => w.Id);
            var workItems = ids.Select(i => new WorkItem {
                Id = i
            });

            HttpClientMock.Setup(c => c.ExecutePost <FlatWorkItemsQueryResult>(It.IsAny <string>(), It.Is <WorkItemsQuery>(q => !q.IsHierarchical), CancellationToken))
            .ReturnsAsync(queryResult)
            .Verifiable();

            HttpClientMock.Setup(c => c.ExecuteGet <CollectionResponse <WorkItem> >(It.Is <string>(u => VerifyWorkItemsUrl(u, fields, ids)), CancellationToken))
            .ReturnsAsync(new CollectionResponse <WorkItem> {
                Value = workItems
            })
            .Verifiable();

            var result = await Client.GetWorkItemsAsync(query, false, CancellationToken);

            result.Should().HaveCount(workItems.Count());
            result.Should().BeEquivalentTo(workItems);

            HttpClientMock.Verify();
        }
예제 #3
0
        /// <inheritdoc />
        public async Task<IEnumerable<WorkItem>> GetWorkItemsAsync(string project, WorkItemsQuery query, CancellationToken cancellationToken = default(CancellationToken))
        {
            var queryResult = await ExecuteQueryAsync(project, query, cancellationToken);
            int[] ids;
            switch (queryResult)
            {
                case FlatWorkItemsQueryResult flat:
                    ids = GetWorkitemIdsFromQuery(flat);
                    break;
                case HierarchicalWorkItemsQueryResult tree:
                    ids = GetWorkitemIdsFromQuery(tree);
                    break;
                default:
                    throw new NotSupportedException($"Query result is of not supported type.");
            }

            if (!ids.Any())
                return Enumerable.Empty<WorkItem>();

            var fieldsString = string.Join(",", queryResult.Columns.Select(c => c.ReferenceName));
            var idsString = string.Join(",", ids);
            var url = VstsUrlBuilder.Create(_instanceName)
                .ForWorkItemsBatch(idsString, project)
                .WithQueryParameter("fields", fieldsString)
                .Build();

            var workitemsResponse = await _httpClient.ExecuteGet<CollectionResponse<WorkItem>>(url, cancellationToken);

            if (workitemsResponse == null)
                return Enumerable.Empty<WorkItem>();

            return workitemsResponse.Value;
        }
예제 #4
0
        public void ExecuteQueryShouldThrowArgumentExceptionIfQueryIsEmpty()
        {
            var query = WorkItemsQuery.Get(string.Empty);

            Client.Awaiting(async c => await c.ExecuteQueryAsync(query))
            .Should()
            .Throw <ArgumentException>();
        }
        public void ExecuteQueryShouldThrowArgumentExceptionIfQueryIsEmpty()
        {
            var query = new WorkItemsQuery(string.Empty);

            _client.Awaiting(async c => await c.ExecuteQueryAsync(ProjectName, query))
            .Should()
            .Throw <ArgumentException>();
        }
예제 #6
0
        private async Task <T> ExecuteQueryInternalAsync <T>(WorkItemsQuery query, CancellationToken cancellationToken)
        {
            ThrowIfArgumentNull(query, nameof(query));

            var url = _urlBuilderFactory.Create()
                      .ForWIQL()
                      .Build(Constants.CurrentWorkItemsApiVersion);

            return(await _httpClient.ExecutePost <T>(url, query, cancellationToken));
        }
예제 #7
0
        public void GetWorkItemsShouldThrowExceptionIfNullQuery()
        {
            var query = WorkItemsQuery.Get("Dummy query");

            HttpClientMock.Setup(c => c.ExecutePost <FlatWorkItemsQueryResult>(It.IsAny <string>(), It.Is <WorkItemsQuery>(q => !q.IsHierarchical), CancellationToken.None))
            .ReturnsAsync((FlatWorkItemsQueryResult)null);

            Client.Awaiting(c => c.GetWorkItemsAsync(query))
            .Should().Throw <NotSupportedException>();
        }
예제 #8
0
        public async Task GetWorkItemsShouldReturnEmptyListOfWorkItemsIfResponseIsNull()
        {
            var query = WorkItemsQuery.Get("Dummy query");

            HttpClientMock.Setup(c => c.ExecutePost <FlatWorkItemsQueryResult>(It.IsAny <string>(), It.Is <WorkItemsQuery>(q => !q.IsHierarchical), CancellationToken.None))
            .ReturnsAsync(new FlatWorkItemsQueryResult {
                Columns = Enumerable.Empty <ColumnReference>(), WorkItems = Enumerable.Empty <WorkItemReference>()
            });
            HttpClientMock.Setup(c => c.ExecuteGet <CollectionResponse <WorkItem> >(It.IsAny <string>(), CancellationToken.None))
            .ReturnsAsync((CollectionResponse <WorkItem>)null);

            var result = await Client.GetWorkItemsAsync(query);

            result.Should().HaveCount(0);
        }
        public async Task ExecuteQueryShouldReturnCorrectResultType(bool isHierarchical, Type expectedReturnType)
        {
            var query = new WorkItemsQuery("Dummy query", isHierarchical);

            _httpClientMock.Setup(c => c.ExecutePost <HierarchicalWorkItemsQueryResult>(It.Is <string>(u => VerifyWiqlQueryUrl(u)), It.Is <WorkItemsQuery>(q => q.IsHierarchical), _cancellationToken))
            .ReturnsAsync(new HierarchicalWorkItemsQueryResult());
            _httpClientMock.Setup(c => c.ExecutePost <FlatWorkItemsQueryResult>(It.Is <string>(u => VerifyWiqlQueryUrl(u)), It.Is <WorkItemsQuery>(q => !q.IsHierarchical), _cancellationToken))
            .ReturnsAsync(new FlatWorkItemsQueryResult());

            var result = await _client.ExecuteQueryAsync(ProjectName, query, _cancellationToken);

            result.Should().BeOfType(expectedReturnType);
            _httpClientMock.Verify(c => c.ExecutePost <HierarchicalWorkItemsQueryResult>(It.Is <string>(u => VerifyWiqlQueryUrl(u)), It.Is <WorkItemsQuery>(q => q.IsHierarchical), _cancellationToken),
                                   Times.Exactly(isHierarchical ? 1 : 0));
            _httpClientMock.Verify(c => c.ExecutePost <FlatWorkItemsQueryResult>(It.Is <string>(u => VerifyWiqlQueryUrl(u)), It.Is <WorkItemsQuery>(q => !q.IsHierarchical), _cancellationToken),
                                   Times.Exactly(!isHierarchical ? 1 : 0));
        }
예제 #10
0
        /// <inheritdoc />
        public async Task <WorkItemsQueryResult> ExecuteQueryAsync(WorkItemsQuery query, CancellationToken cancellationToken = default(CancellationToken))
        {
            ThrowIfArgumentNull(query, nameof(query));
            ThrowIfArgumentNullOrEmpty(query.Query, "Query cannot be empty.");

            var url = _urlBuilderFactory.Create()
                      .ForWIQL()
                      .Build(Constants.CurrentWorkItemsApiVersion);

            _logger.LogDebug("Requesting {0}", url);

            if (query.IsHierarchical)
            {
                return(await _httpClient.ExecutePost <HierarchicalWorkItemsQueryResult>(url, query, cancellationToken));
            }

            return(await _httpClient.ExecutePost <FlatWorkItemsQueryResult>(url, query, cancellationToken));
        }
예제 #11
0
        public async Task <HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
        {
            var config = await _mediator.Request <GetFirstOrganization, OrganizationViewModel>();

            if (config == null || config.Identity.Equals(Guid.Empty))
            {
                return(HealthCheckResult.Unhealthy("ADO default identity is not set."));
            }

            if (string.IsNullOrEmpty(config.Name))
            {
                return(HealthCheckResult.Unhealthy("ADO instance name is not set."));
            }

            var identity = await _mediator.Request <GetIdentityById, IdentityViewModel>(new GetIdentityById { Id = config.Identity });

            if (identity == null || string.IsNullOrEmpty(identity.Token))
            {
                return(HealthCheckResult.Unhealthy("Token is empty."));
            }

            if (identity.ExpirationDate < DateTime.UtcNow.AddDays(15))
            {
                return(HealthCheckResult.Degraded($"Default token will expire on {identity.ExpirationDate.ToString("MM/dd/yyyy")}"));
            }

            if (identity.ExpirationDate < DateTime.UtcNow)
            {
                return(HealthCheckResult.Unhealthy("Default token has expired."));
            }

            try
            {
                var client = VstsClient.Get(new OnlineUrlBuilderFactory(config.Name), identity.Token);
                await client.ExecuteQueryAsync(WorkItemsQuery.Get(@"SELECT [System.Id] FROM WorkItems WHERE (ID < 1)"));
            }
            catch (Exception ex)
            {
                return(HealthCheckResult.Unhealthy("Exception while fetching from ADO", ex));
            }

            return(HealthCheckResult.Healthy("AzureDevOps is OK"));
        }
예제 #12
0
        public async Task GetWorkItemsShouldReturnEmptyIfNoItemsFound()
        {
            var query       = WorkItemsQuery.Get("Dummy query");
            var queryResult = new FlatWorkItemsQueryResult
            {
                Columns   = new ColumnReference[0],
                WorkItems = new WorkItemReference[0]
            };

            HttpClientMock.Setup(c => c.ExecutePost <FlatWorkItemsQueryResult>(It.IsAny <string>(), It.Is <WorkItemsQuery>(q => !q.IsHierarchical), CancellationToken))
            .ReturnsAsync(queryResult)
            .Verifiable();

            var result = await Client.GetWorkItemsAsync(query, false, CancellationToken);

            result.Should().BeEmpty();

            HttpClientMock.Verify();
            HttpClientMock.Verify(c => c.ExecuteGet <CollectionResponse <WorkItem> >(It.IsAny <string>(), CancellationToken), Times.Never());
        }
예제 #13
0
        public async Task GetWorkItemsShouldComposeCorrectUrlForTreeQueries()
        {
            var query       = new WorkItemsQuery("Dummy query", isHierarchical: true);
            var queryResult = new HierarchicalWorkItemsQueryResult
            {
                Columns           = new[] { new ColumnReference("Id", "System.Id"), new ColumnReference("Title", "System.Title") },
                WorkItemRelations = new[]
                {
                    new WorkItemLink(new WorkItemReference(2), new WorkItemReference(34), "foo"),
                    new WorkItemLink(new WorkItemReference(2), new WorkItemReference(2), "foo"),
                    new WorkItemLink(new WorkItemReference(2), new WorkItemReference(56), "foo")
                }
            };
            var fields = queryResult.Columns.Select(c => c.ReferenceName);
            var ids    = queryResult.WorkItemRelations.Select(w => w.Source.Id)
                         .Union(queryResult.WorkItemRelations.Select(w => w.Target.Id))
                         .Distinct()
                         .ToArray();
            var workItems = ids.Select(i => new WorkItem {
                Id = i
            });

            _httpClientMock.Setup(c => c.ExecutePost <HierarchicalWorkItemsQueryResult>(It.IsAny <string>(), It.Is <WorkItemsQuery>(q => q.IsHierarchical), _cancellationToken))
            .ReturnsAsync(queryResult)
            .Verifiable();

            _httpClientMock.Setup(c => c.ExecuteGet <CollectionResponse <WorkItem> >(It.Is <string>(u => VerifyWorkItemsUrl(u, fields, ids)), _cancellationToken))
            .ReturnsAsync(new CollectionResponse <WorkItem> {
                Value = workItems
            })
            .Verifiable();

            var result = await _client.GetWorkItemsAsync(ProjectName, query, _cancellationToken);

            result.Should().HaveCount(workItems.Count());
            result.Should().BeEquivalentTo(workItems);

            _httpClientMock.Verify();
        }
예제 #14
0
        public void GetWorkItemsShouldNotCatchExceptions()
        {
            var query = WorkItemsQuery.Get("Dummy query");

            // Test 1
            HttpClientMock.Setup(c => c.ExecutePost <FlatWorkItemsQueryResult>(It.IsAny <string>(), It.Is <WorkItemsQuery>(q => !q.IsHierarchical), CancellationToken.None))
            .Throws <Exception>();

            Client.Awaiting(c => c.GetWorkItemsAsync(query))
            .Should().Throw <Exception>();

            // Test 2
            HttpClientMock.Setup(c => c.ExecutePost <FlatWorkItemsQueryResult>(It.IsAny <string>(), It.Is <WorkItemsQuery>(q => !q.IsHierarchical), CancellationToken.None))
            .ReturnsAsync(new FlatWorkItemsQueryResult
            {
                Columns   = new[] { new ColumnReference("Title", "System.Title") },
                WorkItems = new[] { new WorkItemReference(1) }
            });
            HttpClientMock.Setup(c => c.ExecuteGet <CollectionResponse <WorkItem> >(It.IsAny <string>(), CancellationToken.None))
            .Throws(new Exception());

            Client.Awaiting(c => c.GetWorkItemsAsync(query))
            .Should().Throw <Exception>();
        }
예제 #15
0
        /// <inheritdoc />
        public async Task <HierarchicalWorkItemsQueryResult> ExecuteHierarchicalQueryAsync(string query, CancellationToken cancellationToken = default(CancellationToken))
        {
            var result = await ExecuteQueryAsync(WorkItemsQuery.Get(query, isHierarchical: true), cancellationToken);

            return(result as HierarchicalWorkItemsQueryResult);
        }
예제 #16
0
        /// <inheritdoc />
        public async Task <WorkItemsQueryResult> ExecuteQueryAndExpandAsync(string query, bool expandFields, CancellationToken cancellationToken = default(CancellationToken))
        {
            ThrowIfArgumentNullOrEmpty(query, nameof(query));

            return(await ExecuteQueryAndExpandInternal(async() => await ExecuteQueryInternalAsync <JObject>(WorkItemsQuery.Get(query), cancellationToken), expandFields, cancellationToken));
        }