gerrit: add GetChange API call

GetChange returns details about a specific change, and we need it for
CL 46390.

Change-Id: I0047e7170e4c9f822663640e28ee4eaf24b184de
Reviewed-on: https://go-review.googlesource.com/48553
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/gerrit/gerrit_test.go b/gerrit/gerrit_test.go
index f33f7b7..a7f0414 100644
--- a/gerrit/gerrit_test.go
+++ b/gerrit/gerrit_test.go
@@ -6,9 +6,11 @@
 
 import (
 	"context"
+	"io"
 	"net/http"
 	"net/http/httptest"
 	"net/url"
+	"strings"
 	"testing"
 	"time"
 )
@@ -89,3 +91,89 @@
 		t.Errorf("expected DeadlineExceeded error, got %v", uerr.Err)
 	}
 }
+
+var getChangeResponse = []byte(`)]}'
+{
+  "id": "build~master~I92989e0231299ed305ddfbbe6034d293f1c87470",
+  "project": "build",
+  "branch": "master",
+  "hashtags": [],
+  "change_id": "I92989e0231299ed305ddfbbe6034d293f1c87470",
+  "subject": "devapp: fix tests",
+  "status": "ABANDONED",
+  "created": "2017-07-13 06:09:10.000000000",
+  "updated": "2017-07-14 16:31:32.000000000",
+  "insertions": 1,
+  "deletions": 1,
+  "unresolved_comment_count": 0,
+  "has_review_started": true,
+  "_number": 48330,
+  "owner": {
+    "_account_id": 13437
+  },
+  "messages": [
+    {
+      "id": "f9fcf0ff9eb58fc8edd989f8bbb3500ff73f9b11",
+      "author": {
+        "_account_id": 22285
+      },
+      "real_author": {
+        "_account_id": 22285
+      },
+      "date": "2017-07-13 06:14:48.000000000",
+      "message": "Patch Set 1:\n\nCheck out https://go-review.googlesource.com/c/48350/ :)",
+      "_revision_number": 1
+    }
+  ]
+}`)
+
+func TestGetChange(t *testing.T) {
+	hitServer := false
+	uri := ""
+	s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		hitServer = true
+		uri = r.URL.RequestURI()
+		w.Header().Set("Content-Type", "application/json; charset=UTF-8")
+		w.WriteHeader(200)
+		w.Write(getChangeResponse)
+	}))
+	defer s.Close()
+	c := NewClient(s.URL, NoAuth)
+	info, err := c.GetChange(context.Background(), 48330, QueryChangesOpt{
+		Fields: []string{"MESSAGES"},
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !hitServer {
+		t.Errorf("expected to hit test server, didn't")
+	}
+	if want := "/changes/48330?o=MESSAGES"; uri != want {
+		t.Errorf("expected RequestURI to be %q, got %q", want, uri)
+	}
+	if len(info.Messages) != 1 {
+		t.Errorf("expected message length to be 1, got %d", len(info.Messages))
+	}
+	msg := info.Messages[0].Message
+	if !strings.Contains(msg, "Check out") {
+		t.Errorf("expected to find string in Message, got %s", msg)
+	}
+}
+
+func TestGetChangeError(t *testing.T) {
+	hitServer := false
+	s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		hitServer = true
+		w.Header().Set("Content-Type", "text/plain; charset=UTF-8")
+		w.WriteHeader(404)
+		io.WriteString(w, "Not found: 99999")
+	}))
+	defer s.Close()
+	c := NewClient(s.URL, NoAuth)
+	_, err := c.GetChange(context.Background(), 99999, QueryChangesOpt{
+		Fields: []string{"MESSAGES"},
+	})
+	if err != ErrChangeNotExist {
+		t.Errorf("expected ErrChangeNotExist, got %v", err)
+	}
+}