From f23ddf81f9dc612d2c6d5d5bc66d1973edd55a3e Mon Sep 17 00:00:00 2001 From: Gabriel Weyer Date: Sun, 4 May 2014 10:46:35 +1000 Subject: [PATCH] Finalized integration testing for review comments --- .../Clients/IObservablePullRequestsClient.cs | 5 + .../Clients/ObservablePullRequestsClient.cs | 6 + Octokit.Reactive/IObservableGitHubClient.cs | 1 + Octokit.Reactive/ObservableGitHubClient.cs | 2 + .../PullRequestReviewCommentsClientTests.cs | 336 +++++++++++++----- .../Request/PullRequestReviewCommentCreate.cs | 6 +- .../Request/PullRequestReviewCommentEdit.cs | 4 +- .../PullRequestReviewCommentReplyCreate.cs | 4 +- .../PullRequestReviewCommentRequest.cs | 2 + .../Response/PullRequestReviewComment.cs | 2 + build.fsx | 2 +- 11 files changed, 279 insertions(+), 91 deletions(-) diff --git a/Octokit.Reactive/Clients/IObservablePullRequestsClient.cs b/Octokit.Reactive/Clients/IObservablePullRequestsClient.cs index 739793c8..7fd79c95 100644 --- a/Octokit.Reactive/Clients/IObservablePullRequestsClient.cs +++ b/Octokit.Reactive/Clients/IObservablePullRequestsClient.cs @@ -5,6 +5,11 @@ namespace Octokit.Reactive { public interface IObservablePullRequestsClient { + /// + /// Client for managing comments. + /// + IObservablePullRequestReviewCommentsClient Comment { get; } + /// /// Gets a single Pull Request by number. /// diff --git a/Octokit.Reactive/Clients/ObservablePullRequestsClient.cs b/Octokit.Reactive/Clients/ObservablePullRequestsClient.cs index 33f749b2..ca8cd05d 100644 --- a/Octokit.Reactive/Clients/ObservablePullRequestsClient.cs +++ b/Octokit.Reactive/Clients/ObservablePullRequestsClient.cs @@ -9,12 +9,18 @@ namespace Octokit.Reactive readonly IPullRequestsClient _client; readonly IConnection _connection; + /// + /// Client for managing comments. + /// + public IObservablePullRequestReviewCommentsClient Comment { get; private set; } + public ObservablePullRequestsClient(IGitHubClient client) { Ensure.ArgumentNotNull(client, "client"); _client = client.Repository.PullRequest; _connection = client.Connection; + Comment = new ObservablePullRequestReviewCommentsClient(client); } /// diff --git a/Octokit.Reactive/IObservableGitHubClient.cs b/Octokit.Reactive/IObservableGitHubClient.cs index c8983ff8..e6374a0c 100644 --- a/Octokit.Reactive/IObservableGitHubClient.cs +++ b/Octokit.Reactive/IObservableGitHubClient.cs @@ -10,6 +10,7 @@ IObservableMiscellaneousClient Miscellaneous { get; } IObservableOauthClient Oauth { get; } IObservableOrganizationsClient Organization { get; } + IObservablePullRequestsClient PullRequest { get; } IObservableRepositoriesClient Repository { get; } IObservableGistsClient Gist { get; } IObservableReleasesClient Release { get; } diff --git a/Octokit.Reactive/ObservableGitHubClient.cs b/Octokit.Reactive/ObservableGitHubClient.cs index cba117f2..dc5c3d03 100644 --- a/Octokit.Reactive/ObservableGitHubClient.cs +++ b/Octokit.Reactive/ObservableGitHubClient.cs @@ -38,6 +38,7 @@ namespace Octokit.Reactive Notification = new ObservableNotificationsClient(gitHubClient); Oauth = new ObservableOauthClient(gitHubClient); Organization = new ObservableOrganizationsClient(gitHubClient); + PullRequest = new ObservablePullRequestsClient(gitHubClient); Repository = new ObservableRepositoriesClient(gitHubClient); SshKey = new ObservableSshKeysClient(gitHubClient); User = new ObservableUsersClient(gitHubClient); @@ -58,6 +59,7 @@ namespace Octokit.Reactive public IObservableMiscellaneousClient Miscellaneous { get; private set; } public IObservableOauthClient Oauth { get; private set; } public IObservableOrganizationsClient Organization { get; private set; } + public IObservablePullRequestsClient PullRequest { get; private set; } public IObservableRepositoriesClient Repository { get; private set; } public IObservableGistsClient Gist { get; private set; } public IObservableReleasesClient Release { get; private set; } diff --git a/Octokit.Tests.Integration/Clients/PullRequestReviewCommentsClientTests.cs b/Octokit.Tests.Integration/Clients/PullRequestReviewCommentsClientTests.cs index a8cf2c14..4cc6fd24 100644 --- a/Octokit.Tests.Integration/Clients/PullRequestReviewCommentsClientTests.cs +++ b/Octokit.Tests.Integration/Clients/PullRequestReviewCommentsClientTests.cs @@ -11,16 +11,15 @@ using Xunit; public class PullRequestReviewCommentsClientTests : IDisposable { IGitHubClient _gitHubClient; - Repository _repository; + List _repositoriesToDelete = new List(); IPullRequestReviewCommentsClient _client; - string _ownerName; - string _repoName; - string _branchName; + const string _branchName = "heads/new-branch"; + const string _path = "CONTRIBUTING.md"; + string _repoName; int _pullRequestNumber; string _pullRequestCommitId; - string _path; public PullRequestReviewCommentsClientTests() { @@ -29,109 +28,276 @@ public class PullRequestReviewCommentsClientTests : IDisposable Credentials = Helper.Credentials }; - // Creating a repository + _client = _gitHubClient.PullRequest.Comment; - _repoName = Helper.MakeNameWithTimestamp("public-repo"); - _repository = _gitHubClient.Repository.Create(new NewRepository { Name = _repoName }).Result; - _ownerName = _repository.Owner.Name; + // We'll create a pull request that can be used by most tests + var pullRequestData = CreatePullRequest().Result; + + _repositoriesToDelete.Add(pullRequestData.Repository); + + _repoName = pullRequestData.RepoName; + _pullRequestNumber = pullRequestData.PullRequestNumber; + _pullRequestCommitId = pullRequestData.PullRequestCommitId; + } + + [IntegrationTest] + public async Task CanCreateAndRetrieveComment() + { + var body = "A review comment message"; + var position = 1; + + var createdCommentId = await CreateComment(body, position); + + var commentFromGitHub = await _client.GetComment(Helper.UserName, _repoName, createdCommentId); + + AssertComment(commentFromGitHub, body, position); + } + + [IntegrationTest] + public async Task CanEditComment() + { + var body = "A new review comment message"; + var position = 1; + + var createdCommentId = await CreateComment(body, position); + + var edit = new PullRequestReviewCommentEdit("Edited Comment"); + + var editedComment = await _client.Edit(Helper.UserName, _repoName, createdCommentId, edit); + + var commentFromGitHub = await _client.GetComment(Helper.UserName, _repoName, editedComment.Id); + + AssertComment(commentFromGitHub, edit.Body, position); + } + + [IntegrationTest] + public async Task CanDeleteComment() + { + var body = "A new review comment message"; + var position = 1; + + var createdCommentId = await CreateComment(body, position); + + var edit = new PullRequestReviewCommentEdit("Edited Comment"); + + Assert.DoesNotThrow(async () => { await _client.Delete(Helper.UserName, _repoName, createdCommentId); }); + } + + [IntegrationTest] + public async Task CanCreateReply() + { + var body = "Reply me!"; + var position = 1; + + var createdCommentId = await CreateComment(body, position); + + var reply = new PullRequestReviewCommentReplyCreate("Replied", createdCommentId); + var createdReply = await _client.CreateReply(Helper.UserName, _repoName, _pullRequestNumber, reply); + var createdReplyFromGitHub = await _client.GetComment(Helper.UserName, _repoName, createdReply.Id); + + AssertComment(createdReplyFromGitHub, reply.Body, position); + } + + [IntegrationTest] + public async Task CanGetForPullRequest() + { + var pullRequest = await CreatePullRequest(); + _repositoriesToDelete.Add(pullRequest.Repository); + + var position = 1; + List commentsToCreate = new List { "Comment 1", "Comment 2", "Comment 3" }; + + await CreateComments(commentsToCreate, position, pullRequest.RepoName, pullRequest.PullRequestCommitId, pullRequest.PullRequestNumber); + + var pullRequestComments = await _client.GetForPullRequest(Helper.UserName, pullRequest.RepoName, pullRequest.PullRequestNumber); + + AssertComments(pullRequestComments, commentsToCreate, position); + } + + [IntegrationTest] + public async Task CanGetForRepository() + { + var pullRequest = await CreatePullRequest(); + _repositoriesToDelete.Add(pullRequest.Repository); + + var position = 1; + List commentsToCreate = new List { "Comment One", "Comment Two" }; + + await CreateComments(commentsToCreate, position, pullRequest.RepoName, pullRequest.PullRequestCommitId, pullRequest.PullRequestNumber); + + var pullRequestComments = await _client.GetForRepository(Helper.UserName, pullRequest.RepoName); + + AssertComments(pullRequestComments, commentsToCreate, position); + } + + [IntegrationTest] + public async Task CanGetForRepositoryAscendingSort() + { + var pullRequest = await CreatePullRequest(); + _repositoriesToDelete.Add(pullRequest.Repository); + + var position = 1; + List commentsToCreate = new List { "Comment One", "Comment Two", "Comment Three", "Comment Four" }; + + await CreateComments(commentsToCreate, position, pullRequest.RepoName, pullRequest.PullRequestCommitId, pullRequest.PullRequestNumber); + + var pullRequestComments = await _client.GetForRepository(Helper.UserName, pullRequest.RepoName, new PullRequestReviewCommentRequest { Direction = SortDirection.Ascending }); + + AssertComments(pullRequestComments, commentsToCreate, position); + } + + [IntegrationTest] + public async Task CanGetForRepositoryDescendingSort() + { + var pullRequest = await CreatePullRequest(); + _repositoriesToDelete.Add(pullRequest.Repository); + + var position = 1; + List commentsToCreate = new List { "Comment One", "Comment Two", "Comment Three", "Comment Four" }; + + await CreateComments(commentsToCreate, position, pullRequest.RepoName, pullRequest.PullRequestCommitId, pullRequest.PullRequestNumber); + + var pullRequestComments = await _client.GetForRepository(Helper.UserName, pullRequest.RepoName, new PullRequestReviewCommentRequest { Direction = SortDirection.Descending }); + + commentsToCreate.Reverse(); + AssertComments(pullRequestComments, commentsToCreate, position); + } + + public void Dispose() + { + foreach (var repo in _repositoriesToDelete) + { + Helper.DeleteRepo(repo); + } + } + + private async Task CreateComment(string body, int position) + { + return await CreateComment(body, position, _repoName, _pullRequestCommitId, _pullRequestNumber); + } + + private async Task CreateComment(string body, int position, string repoName, string pullRequestCommitId, int pullRequestNumber) + { + var comment = new PullRequestReviewCommentCreate(body, pullRequestCommitId, _path, position); + + var createdComment = await _client.Create(Helper.UserName, repoName, pullRequestNumber, comment); + + AssertComment(createdComment, body, position); + + return createdComment.Id; + } + + private async Task CreateComments(List comments, int position, string repoName, string pullRequestCommitId, int pullRequestNumber) + { + foreach (var comment in comments) + { + await CreateComment(comment, position, repoName, pullRequestCommitId, pullRequestNumber); + } + } + + private void AssertComment(PullRequestReviewComment comment, string body, int position) + { + Assert.NotNull(comment); + Assert.Equal(body, comment.Body); + Assert.Equal(position, comment.Position); + } + + private void AssertComments(IReadOnlyList comments, List bodies, int position) + { + Assert.Equal(bodies.Count, comments.Count); + + for (int i = 0; i < bodies.Count; i = i + 1) + { + AssertComment(comments[i], bodies[i], position); + } + } + + private async Task CreateRepository(string repoName) + { + return await _gitHubClient.Repository.Create(new NewRepository { Name = repoName, AutoInit = true }); + } + + /// + /// Creates the base state for testing (creates a repo, a commit in master, a branch, a commit in the branch and a pull request) + /// + /// + private async Task CreatePullRequest() + { + var repoName = Helper.MakeNameWithTimestamp("test-repo"); + var repository = await CreateRepository(repoName); + + // Creating a commit in master + + var createdCommitInMaster = await CreateCommit(repoName, "Hello World!", "README.md", "heads/master", "A master commit message"); + + // Creating a branch + + var newBranch = new NewReference("refs/" + _branchName, createdCommitInMaster.Sha); + var branchReference = await _gitHubClient.GitDatabase.Reference.Create(Helper.UserName, repoName, newBranch); + + // Creating a commit in the branch + + var createdCommitInBranch = await CreateCommit(repoName, "Hello from the fork!", _path, _branchName, "A branch commit message"); + + // Creating a pull request + + var pullRequest = new NewPullRequest("Nice title for the pull request", _branchName, "master"); + var createdPullRequest = await _gitHubClient.PullRequest.Create(Helper.UserName, repoName, pullRequest); + + var data = new PullRequestData + { + PullRequestCommitId = createdCommitInBranch.Sha, + PullRequestNumber = createdPullRequest.Number, + RepoName = repoName, + Repository = repository, + }; + + return data; + } + + private async Task CreateCommit(string repoName, string blobContent, string treePath, string reference, string commitMessage) + { // Creating a blob var blob = new NewBlob { - Content = "Hello World!", + Content = blobContent, Encoding = EncodingType.Utf8 }; - var createdBlob = _gitHubClient.GitDatabase.Blob.Create(_ownerName, _repoName, blob).Result; + var createdBlob = await _gitHubClient.GitDatabase.Blob.Create(Helper.UserName, repoName, blob); // Creating a tree - var treeSha = createdBlob.Sha; - var newTree = new NewTree(); newTree.Tree.Add(new NewTreeItem { Type = TreeType.Blob, Mode = FileMode.File, - Path = "README.md", - Sha = treeSha, + Path = treePath, + Sha = createdBlob.Sha, }); - var createdTree = _gitHubClient.GitDatabase.Tree.Create(_ownerName, _repoName, newTree).Result; + var createdTree = await _gitHubClient.GitDatabase.Tree.Create(Helper.UserName, repoName, newTree); + var treeSha = createdTree.Sha; // Creating a commit - var commit = new NewCommit("A nice commit message", treeSha, Enumerable.Empty()); + var parent = await _gitHubClient.GitDatabase.Reference.Get(Helper.UserName, repoName, reference); + var commit = new NewCommit(commitMessage, treeSha, parent.Object.Sha); - var createdCommit = _gitHubClient.GitDatabase.Commit.Create(_ownerName, _repoName, commit).Result; + var createdCommit = await _gitHubClient.GitDatabase.Commit.Create(Helper.UserName, repoName, commit); + await _gitHubClient.GitDatabase.Reference.Update(Helper.UserName, repoName, reference, new ReferenceUpdate(createdCommit.Sha)); - // Creating a branch - - var newBranch = new NewReference("refs/heads/new-branch", createdCommit.Sha); - var reference = _gitHubClient.GitDatabase.Reference.Create(_ownerName, _repoName, newBranch).Result; - _branchName = reference.Ref; - - // Creating a blob in the branch - - var pullRequestBlob = new NewBlob - { - Content = "Hello from the fork!", - Encoding = EncodingType.Utf8 - }; - - var createdPullRequestBlob = _gitHubClient.GitDatabase.Blob.Create(_ownerName, _branchName, pullRequestBlob).Result; - - // Creating a tree in the branch - - var pullRequestTreeSha = createdPullRequestBlob.Sha; - _path = "CONTRIBUTING.md"; - - var pullRequestTree = new NewTree(); - pullRequestTree.Tree.Add(new NewTreeItem - { - Type = TreeType.Blob, - Mode = FileMode.File, - Path = _path, - Sha = pullRequestTreeSha, - }); - - var createdPullRequestTree = _gitHubClient.GitDatabase.Tree.Create(_ownerName, _branchName, pullRequestTree).Result; - - // Creating a commit in the branch - - var pullRequestcommit = new NewCommit("A pull request commit message", pullRequestTreeSha, Enumerable.Empty()); - - var createdPullRequestCommit = _gitHubClient.GitDatabase.Commit.Create(_ownerName, _branchName, pullRequestcommit).Result; - _pullRequestCommitId = createdPullRequestCommit.Sha; - - // Creating a pull request - - // TODO Not Implemented: http://developer.github.com/v3/pulls/#create-a-pull-request - _pullRequestNumber = 0; - - _client = _gitHubClient.PullRequest.Comment; - } - - [IntegrationTest(Skip = "Requires Pull Request Api implementation")] - public async Task CanCreateAndRetrieveReviewComment() - { - var pullRequestReviewComment = new PullRequestReviewCommentCreate("A review comment message", _pullRequestCommitId, _path, 1); - - var createdComment = await _client.Create(_ownerName, _repoName, _pullRequestNumber, pullRequestReviewComment); - - Assert.NotNull(createdComment); - Assert.Equal(pullRequestReviewComment.Body, createdComment.Body); - - var commentFromGitHub = await _client.GetComment(_ownerName, _repoName, createdComment.Id); - - Assert.NotNull(commentFromGitHub); - Assert.Equal(pullRequestReviewComment.Body, commentFromGitHub.Body); - } - - public void Dispose() - { - Helper.DeleteRepo(_repository); - // TODO Ensure that it deletes the branch too + return createdCommit; } } + +class PullRequestData +{ + public Repository Repository { get; set; } + public int PullRequestNumber { get; set; } + public string PullRequestCommitId { get; set; } + public string RepoName { get; set; } +} \ No newline at end of file diff --git a/Octokit/Models/Request/PullRequestReviewCommentCreate.cs b/Octokit/Models/Request/PullRequestReviewCommentCreate.cs index 2a877a6f..d9ae04b8 100644 --- a/Octokit/Models/Request/PullRequestReviewCommentCreate.cs +++ b/Octokit/Models/Request/PullRequestReviewCommentCreate.cs @@ -1,7 +1,9 @@ -using Octokit.Internal; +using System.Diagnostics; +using Octokit.Internal; namespace Octokit { + [DebuggerDisplay("{DebuggerDisplay,nq}")] public class PullRequestReviewCommentCreate : RequestParameters { /// @@ -42,7 +44,5 @@ namespace Octokit /// The line index in the diff to comment on. /// public int Position { get; private set; } - - } } diff --git a/Octokit/Models/Request/PullRequestReviewCommentEdit.cs b/Octokit/Models/Request/PullRequestReviewCommentEdit.cs index 933cafce..f8cc7ba1 100644 --- a/Octokit/Models/Request/PullRequestReviewCommentEdit.cs +++ b/Octokit/Models/Request/PullRequestReviewCommentEdit.cs @@ -1,6 +1,8 @@ - +using System.Diagnostics; + namespace Octokit { + [DebuggerDisplay("{DebuggerDisplay,nq}")] public class PullRequestReviewCommentEdit : RequestParameters { /// diff --git a/Octokit/Models/Request/PullRequestReviewCommentReplyCreate.cs b/Octokit/Models/Request/PullRequestReviewCommentReplyCreate.cs index 342b5571..221ea677 100644 --- a/Octokit/Models/Request/PullRequestReviewCommentReplyCreate.cs +++ b/Octokit/Models/Request/PullRequestReviewCommentReplyCreate.cs @@ -1,7 +1,9 @@ -using Octokit.Internal; +using System.Diagnostics; +using Octokit.Internal; namespace Octokit { + [DebuggerDisplay("{DebuggerDisplay,nq}")] public class PullRequestReviewCommentReplyCreate : RequestParameters { /// diff --git a/Octokit/Models/Request/PullRequestReviewCommentRequest.cs b/Octokit/Models/Request/PullRequestReviewCommentRequest.cs index ada12064..4bd22d0f 100644 --- a/Octokit/Models/Request/PullRequestReviewCommentRequest.cs +++ b/Octokit/Models/Request/PullRequestReviewCommentRequest.cs @@ -1,7 +1,9 @@ using System; +using System.Diagnostics; namespace Octokit { + [DebuggerDisplay("{DebuggerDisplay,nq}")] public class PullRequestReviewCommentRequest : RequestParameters { public PullRequestReviewCommentRequest() diff --git a/Octokit/Models/Response/PullRequestReviewComment.cs b/Octokit/Models/Response/PullRequestReviewComment.cs index 14807e07..03e6b418 100644 --- a/Octokit/Models/Response/PullRequestReviewComment.cs +++ b/Octokit/Models/Response/PullRequestReviewComment.cs @@ -1,7 +1,9 @@ using System; +using System.Diagnostics; namespace Octokit { + [DebuggerDisplay("{DebuggerDisplay,nq}")] public class PullRequestReviewComment { /// diff --git a/build.fsx b/build.fsx index 7b914e33..21ab54b3 100644 --- a/build.fsx +++ b/build.fsx @@ -87,7 +87,7 @@ Target "IntegrationTests" (fun _ -> XmlOutput = true Verbose = false OutputDir = testResultsDir - TimeOut = TimeSpan.FromMinutes 10.0 }) + TimeOut = TimeSpan.FromMinutes 20.0 }) else "The integration tests were skipped because the OCTOKIT_GITHUBUSERNAME and OCTOKIT_GITHUBPASSWORD environment variables are not set. " + "Please configure these environment variables for a GitHub test account (DO NOT USE A \"REAL\" ACCOUNT)."