vendor: revendor

This commit is contained in:
Eric Chiang
2016-12-22 11:39:28 -08:00
parent d87a4c35b9
commit 1451213dd7
268 changed files with 484 additions and 59530 deletions

View File

@@ -1,9 +0,0 @@
// Copyright 2014 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// +build race
package internal
func init() { raceDetector = true }

View File

@@ -1,467 +0,0 @@
// Copyright 2014 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// +build !appengine
package internal
import (
"bufio"
"bytes"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/url"
"os"
"os/exec"
"strings"
"sync/atomic"
"testing"
"time"
"github.com/golang/protobuf/proto"
netcontext "golang.org/x/net/context"
basepb "google.golang.org/appengine/internal/base"
remotepb "google.golang.org/appengine/internal/remote_api"
)
const testTicketHeader = "X-Magic-Ticket-Header"
func init() {
ticketHeader = testTicketHeader
}
type fakeAPIHandler struct {
hang chan int // used for RunSlowly RPC
LogFlushes int32 // atomic
}
func (f *fakeAPIHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
writeResponse := func(res *remotepb.Response) {
hresBody, err := proto.Marshal(res)
if err != nil {
http.Error(w, fmt.Sprintf("Failed encoding API response: %v", err), 500)
return
}
w.Write(hresBody)
}
if r.URL.Path != "/rpc_http" {
http.NotFound(w, r)
return
}
hreqBody, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, fmt.Sprintf("Bad body: %v", err), 500)
return
}
apiReq := &remotepb.Request{}
if err := proto.Unmarshal(hreqBody, apiReq); err != nil {
http.Error(w, fmt.Sprintf("Bad encoded API request: %v", err), 500)
return
}
if *apiReq.RequestId != "s3cr3t" {
writeResponse(&remotepb.Response{
RpcError: &remotepb.RpcError{
Code: proto.Int32(int32(remotepb.RpcError_SECURITY_VIOLATION)),
Detail: proto.String("bad security ticket"),
},
})
return
}
if got, want := r.Header.Get(dapperHeader), "trace-001"; got != want {
writeResponse(&remotepb.Response{
RpcError: &remotepb.RpcError{
Code: proto.Int32(int32(remotepb.RpcError_BAD_REQUEST)),
Detail: proto.String(fmt.Sprintf("trace info = %q, want %q", got, want)),
},
})
return
}
service, method := *apiReq.ServiceName, *apiReq.Method
var resOut proto.Message
if service == "actordb" && method == "LookupActor" {
req := &basepb.StringProto{}
res := &basepb.StringProto{}
if err := proto.Unmarshal(apiReq.Request, req); err != nil {
http.Error(w, fmt.Sprintf("Bad encoded request: %v", err), 500)
return
}
if *req.Value == "Doctor Who" {
res.Value = proto.String("David Tennant")
}
resOut = res
}
if service == "errors" {
switch method {
case "Non200":
http.Error(w, "I'm a little teapot.", 418)
return
case "ShortResponse":
w.Header().Set("Content-Length", "100")
w.Write([]byte("way too short"))
return
case "OverQuota":
writeResponse(&remotepb.Response{
RpcError: &remotepb.RpcError{
Code: proto.Int32(int32(remotepb.RpcError_OVER_QUOTA)),
Detail: proto.String("you are hogging the resources!"),
},
})
return
case "RunSlowly":
// TestAPICallRPCFailure creates f.hang, but does not strobe it
// until Call returns with remotepb.RpcError_CANCELLED.
// This is here to force a happens-before relationship between
// the httptest server handler and shutdown.
<-f.hang
resOut = &basepb.VoidProto{}
}
}
if service == "logservice" && method == "Flush" {
// Pretend log flushing is slow.
time.Sleep(50 * time.Millisecond)
atomic.AddInt32(&f.LogFlushes, 1)
resOut = &basepb.VoidProto{}
}
encOut, err := proto.Marshal(resOut)
if err != nil {
http.Error(w, fmt.Sprintf("Failed encoding response: %v", err), 500)
return
}
writeResponse(&remotepb.Response{
Response: encOut,
})
}
func setup() (f *fakeAPIHandler, c *context, cleanup func()) {
f = &fakeAPIHandler{}
srv := httptest.NewServer(f)
u, err := url.Parse(srv.URL + apiPath)
if err != nil {
panic(fmt.Sprintf("url.Parse(%q): %v", srv.URL+apiPath, err))
}
return f, &context{
req: &http.Request{
Header: http.Header{
ticketHeader: []string{"s3cr3t"},
dapperHeader: []string{"trace-001"},
},
},
apiURL: u,
}, srv.Close
}
func TestAPICall(t *testing.T) {
_, c, cleanup := setup()
defer cleanup()
req := &basepb.StringProto{
Value: proto.String("Doctor Who"),
}
res := &basepb.StringProto{}
err := Call(toContext(c), "actordb", "LookupActor", req, res)
if err != nil {
t.Fatalf("API call failed: %v", err)
}
if got, want := *res.Value, "David Tennant"; got != want {
t.Errorf("Response is %q, want %q", got, want)
}
}
func TestAPICallRPCFailure(t *testing.T) {
f, c, cleanup := setup()
defer cleanup()
testCases := []struct {
method string
code remotepb.RpcError_ErrorCode
}{
{"Non200", remotepb.RpcError_UNKNOWN},
{"ShortResponse", remotepb.RpcError_UNKNOWN},
{"OverQuota", remotepb.RpcError_OVER_QUOTA},
{"RunSlowly", remotepb.RpcError_CANCELLED},
}
f.hang = make(chan int) // only for RunSlowly
for _, tc := range testCases {
ctx, _ := netcontext.WithTimeout(toContext(c), 100*time.Millisecond)
err := Call(ctx, "errors", tc.method, &basepb.VoidProto{}, &basepb.VoidProto{})
ce, ok := err.(*CallError)
if !ok {
t.Errorf("%s: API call error is %T (%v), want *CallError", tc.method, err, err)
continue
}
if ce.Code != int32(tc.code) {
t.Errorf("%s: ce.Code = %d, want %d", tc.method, ce.Code, tc.code)
}
if tc.method == "RunSlowly" {
f.hang <- 1 // release the HTTP handler
}
}
}
func TestAPICallDialFailure(t *testing.T) {
// See what happens if the API host is unresponsive.
// This should time out quickly, not hang forever.
_, c, cleanup := setup()
defer cleanup()
// Reset the URL to the production address so that dialing fails.
c.apiURL = apiURL()
start := time.Now()
err := Call(toContext(c), "foo", "bar", &basepb.VoidProto{}, &basepb.VoidProto{})
const max = 1 * time.Second
if taken := time.Since(start); taken > max {
t.Errorf("Dial hang took too long: %v > %v", taken, max)
}
if err == nil {
t.Error("Call did not fail")
}
}
func TestDelayedLogFlushing(t *testing.T) {
f, c, cleanup := setup()
defer cleanup()
http.HandleFunc("/quick_log", func(w http.ResponseWriter, r *http.Request) {
logC := WithContext(netcontext.Background(), r)
fromContext(logC).apiURL = c.apiURL // Otherwise it will try to use the default URL.
Logf(logC, 1, "It's a lovely day.")
w.WriteHeader(200)
w.Write(make([]byte, 100<<10)) // write 100 KB to force HTTP flush
})
r := &http.Request{
Method: "GET",
URL: &url.URL{
Scheme: "http",
Path: "/quick_log",
},
Header: c.req.Header,
Body: ioutil.NopCloser(bytes.NewReader(nil)),
}
w := httptest.NewRecorder()
// Check that log flushing does not hold up the HTTP response.
start := time.Now()
handleHTTP(w, r)
if d := time.Since(start); d > 10*time.Millisecond {
t.Errorf("handleHTTP took %v, want under 10ms", d)
}
const hdr = "X-AppEngine-Log-Flush-Count"
if h := w.HeaderMap.Get(hdr); h != "1" {
t.Errorf("%s header = %q, want %q", hdr, h, "1")
}
if f := atomic.LoadInt32(&f.LogFlushes); f != 0 {
t.Errorf("After HTTP response: f.LogFlushes = %d, want 0", f)
}
// Check that the log flush eventually comes in.
time.Sleep(100 * time.Millisecond)
if f := atomic.LoadInt32(&f.LogFlushes); f != 1 {
t.Errorf("After 100ms: f.LogFlushes = %d, want 1", f)
}
}
func TestRemoteAddr(t *testing.T) {
var addr string
http.HandleFunc("/remote_addr", func(w http.ResponseWriter, r *http.Request) {
addr = r.RemoteAddr
})
testCases := []struct {
headers http.Header
addr string
}{
{http.Header{"X-Appengine-User-Ip": []string{"10.5.2.1"}}, "10.5.2.1:80"},
{http.Header{"X-Appengine-Remote-Addr": []string{"1.2.3.4"}}, "1.2.3.4:80"},
{http.Header{"X-Appengine-Remote-Addr": []string{"1.2.3.4:8080"}}, "1.2.3.4:8080"},
{
http.Header{"X-Appengine-Remote-Addr": []string{"2401:fa00:9:1:7646:a0ff:fe90:ca66"}},
"[2401:fa00:9:1:7646:a0ff:fe90:ca66]:80",
},
{
http.Header{"X-Appengine-Remote-Addr": []string{"[::1]:http"}},
"[::1]:http",
},
{http.Header{}, "127.0.0.1:80"},
}
for _, tc := range testCases {
r := &http.Request{
Method: "GET",
URL: &url.URL{Scheme: "http", Path: "/remote_addr"},
Header: tc.headers,
Body: ioutil.NopCloser(bytes.NewReader(nil)),
}
handleHTTP(httptest.NewRecorder(), r)
if addr != tc.addr {
t.Errorf("Header %v, got %q, want %q", tc.headers, addr, tc.addr)
}
}
}
func TestPanickingHandler(t *testing.T) {
http.HandleFunc("/panic", func(http.ResponseWriter, *http.Request) {
panic("whoops!")
})
r := &http.Request{
Method: "GET",
URL: &url.URL{Scheme: "http", Path: "/panic"},
Body: ioutil.NopCloser(bytes.NewReader(nil)),
}
rec := httptest.NewRecorder()
handleHTTP(rec, r)
if rec.Code != 500 {
t.Errorf("Panicking handler returned HTTP %d, want HTTP %d", rec.Code, 500)
}
}
var raceDetector = false
func TestAPICallAllocations(t *testing.T) {
if raceDetector {
t.Skip("not running under race detector")
}
// Run the test API server in a subprocess so we aren't counting its allocations.
u, cleanup := launchHelperProcess(t)
defer cleanup()
c := &context{
req: &http.Request{
Header: http.Header{
ticketHeader: []string{"s3cr3t"},
dapperHeader: []string{"trace-001"},
},
},
apiURL: u,
}
req := &basepb.StringProto{
Value: proto.String("Doctor Who"),
}
res := &basepb.StringProto{}
var apiErr error
avg := testing.AllocsPerRun(100, func() {
ctx, _ := netcontext.WithTimeout(toContext(c), 100*time.Millisecond)
if err := Call(ctx, "actordb", "LookupActor", req, res); err != nil && apiErr == nil {
apiErr = err // get the first error only
}
})
if apiErr != nil {
t.Errorf("API call failed: %v", apiErr)
}
// Lots of room for improvement...
// TODO(djd): Reduce maximum to 85 once the App Engine SDK is based on 1.6.
const min, max float64 = 70, 90
if avg < min || max < avg {
t.Errorf("Allocations per API call = %g, want in [%g,%g]", avg, min, max)
}
}
func launchHelperProcess(t *testing.T) (apiURL *url.URL, cleanup func()) {
cmd := exec.Command(os.Args[0], "-test.run=TestHelperProcess")
cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
stdin, err := cmd.StdinPipe()
if err != nil {
t.Fatalf("StdinPipe: %v", err)
}
stdout, err := cmd.StdoutPipe()
if err != nil {
t.Fatalf("StdoutPipe: %v", err)
}
if err := cmd.Start(); err != nil {
t.Fatalf("Starting helper process: %v", err)
}
scan := bufio.NewScanner(stdout)
var u *url.URL
for scan.Scan() {
line := scan.Text()
if hp := strings.TrimPrefix(line, helperProcessMagic); hp != line {
var err error
u, err = url.Parse(hp)
if err != nil {
t.Fatalf("Failed to parse %q: %v", hp, err)
}
break
}
}
if err := scan.Err(); err != nil {
t.Fatalf("Scanning helper process stdout: %v", err)
}
if u == nil {
t.Fatal("Helper process never reported")
}
return u, func() {
stdin.Close()
if err := cmd.Wait(); err != nil {
t.Errorf("Helper process did not exit cleanly: %v", err)
}
}
}
const helperProcessMagic = "A lovely helper process is listening at "
// This isn't a real test. It's used as a helper process.
func TestHelperProcess(*testing.T) {
if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
return
}
defer os.Exit(0)
f := &fakeAPIHandler{}
srv := httptest.NewServer(f)
defer srv.Close()
fmt.Println(helperProcessMagic + srv.URL + apiPath)
// Wait for stdin to be closed.
io.Copy(ioutil.Discard, os.Stdin)
}
func TestBackgroundContext(t *testing.T) {
environ := []struct {
key, value string
}{
{"GAE_LONG_APP_ID", "my-app-id"},
{"GAE_MINOR_VERSION", "067924799508853122"},
{"GAE_MODULE_INSTANCE", "0"},
{"GAE_MODULE_NAME", "default"},
{"GAE_MODULE_VERSION", "20150612t184001"},
}
for _, v := range environ {
old := os.Getenv(v.key)
os.Setenv(v.key, v.value)
v.value = old
}
defer func() { // Restore old environment after the test completes.
for _, v := range environ {
if v.value == "" {
os.Unsetenv(v.key)
continue
}
os.Setenv(v.key, v.value)
}
}()
ctx, key := fromContext(BackgroundContext()), "X-Magic-Ticket-Header"
if g, w := ctx.req.Header.Get(key), "my-app-id/default.20150612t184001.0"; g != w {
t.Errorf("%v = %q, want %q", key, g, w)
}
// Check that using the background context doesn't panic.
req := &basepb.StringProto{
Value: proto.String("Doctor Who"),
}
res := &basepb.StringProto{}
Call(BackgroundContext(), "actordb", "LookupActor", req, res) // expected to fail
}

View File

@@ -1,34 +0,0 @@
// Copyright 2011 Google Inc. All Rights Reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
package internal
import (
"testing"
)
func TestAppIDParsing(t *testing.T) {
testCases := []struct {
in string
partition, domain, displayID string
}{
{"simple-app-id", "", "", "simple-app-id"},
{"domain.com:domain-app-id", "", "domain.com", "domain-app-id"},
{"part~partition-app-id", "part", "", "partition-app-id"},
{"part~domain.com:display", "part", "domain.com", "display"},
}
for _, tc := range testCases {
part, dom, dis := parseFullAppID(tc.in)
if part != tc.partition {
t.Errorf("partition of %q: got %q, want %q", tc.in, part, tc.partition)
}
if dom != tc.domain {
t.Errorf("domain of %q: got %q, want %q", tc.in, dom, tc.domain)
}
if dis != tc.displayID {
t.Errorf("displayID of %q: got %q, want %q", tc.in, dis, tc.displayID)
}
}
}

View File

@@ -1,33 +0,0 @@
// Built-in base types for API calls. Primarily useful as return types.
syntax = "proto2";
option go_package = "base";
package appengine.base;
message StringProto {
required string value = 1;
}
message Integer32Proto {
required int32 value = 1;
}
message Integer64Proto {
required int64 value = 1;
}
message BoolProto {
required bool value = 1;
}
message DoubleProto {
required double value = 1;
}
message BytesProto {
required bytes value = 1 [ctype=CORD];
}
message VoidProto {
}

View File

@@ -1,541 +0,0 @@
syntax = "proto2";
option go_package = "datastore";
package appengine;
message Action{}
message PropertyValue {
optional int64 int64Value = 1;
optional bool booleanValue = 2;
optional string stringValue = 3;
optional double doubleValue = 4;
optional group PointValue = 5 {
required double x = 6;
required double y = 7;
}
optional group UserValue = 8 {
required string email = 9;
required string auth_domain = 10;
optional string nickname = 11;
optional string federated_identity = 21;
optional string federated_provider = 22;
}
optional group ReferenceValue = 12 {
required string app = 13;
optional string name_space = 20;
repeated group PathElement = 14 {
required string type = 15;
optional int64 id = 16;
optional string name = 17;
}
}
}
message Property {
enum Meaning {
NO_MEANING = 0;
BLOB = 14;
TEXT = 15;
BYTESTRING = 16;
ATOM_CATEGORY = 1;
ATOM_LINK = 2;
ATOM_TITLE = 3;
ATOM_CONTENT = 4;
ATOM_SUMMARY = 5;
ATOM_AUTHOR = 6;
GD_WHEN = 7;
GD_EMAIL = 8;
GEORSS_POINT = 9;
GD_IM = 10;
GD_PHONENUMBER = 11;
GD_POSTALADDRESS = 12;
GD_RATING = 13;
BLOBKEY = 17;
ENTITY_PROTO = 19;
INDEX_VALUE = 18;
};
optional Meaning meaning = 1 [default = NO_MEANING];
optional string meaning_uri = 2;
required string name = 3;
required PropertyValue value = 5;
required bool multiple = 4;
optional bool searchable = 6 [default=false];
enum FtsTokenizationOption {
HTML = 1;
ATOM = 2;
}
optional FtsTokenizationOption fts_tokenization_option = 8;
optional string locale = 9 [default = "en"];
}
message Path {
repeated group Element = 1 {
required string type = 2;
optional int64 id = 3;
optional string name = 4;
}
}
message Reference {
required string app = 13;
optional string name_space = 20;
required Path path = 14;
}
message User {
required string email = 1;
required string auth_domain = 2;
optional string nickname = 3;
optional string federated_identity = 6;
optional string federated_provider = 7;
}
message EntityProto {
required Reference key = 13;
required Path entity_group = 16;
optional User owner = 17;
enum Kind {
GD_CONTACT = 1;
GD_EVENT = 2;
GD_MESSAGE = 3;
}
optional Kind kind = 4;
optional string kind_uri = 5;
repeated Property property = 14;
repeated Property raw_property = 15;
optional int32 rank = 18;
}
message CompositeProperty {
required int64 index_id = 1;
repeated string value = 2;
}
message Index {
required string entity_type = 1;
required bool ancestor = 5;
repeated group Property = 2 {
required string name = 3;
enum Direction {
ASCENDING = 1;
DESCENDING = 2;
}
optional Direction direction = 4 [default = ASCENDING];
}
}
message CompositeIndex {
required string app_id = 1;
required int64 id = 2;
required Index definition = 3;
enum State {
WRITE_ONLY = 1;
READ_WRITE = 2;
DELETED = 3;
ERROR = 4;
}
required State state = 4;
optional bool only_use_if_required = 6 [default = false];
}
message IndexPostfix {
message IndexValue {
required string property_name = 1;
required PropertyValue value = 2;
}
repeated IndexValue index_value = 1;
optional Reference key = 2;
optional bool before = 3 [default=true];
}
message IndexPosition {
optional string key = 1;
optional bool before = 2 [default=true];
}
message Snapshot {
enum Status {
INACTIVE = 0;
ACTIVE = 1;
}
required int64 ts = 1;
}
message InternalHeader {
optional string qos = 1;
}
message Transaction {
optional InternalHeader header = 4;
required fixed64 handle = 1;
required string app = 2;
optional bool mark_changes = 3 [default = false];
}
message Query {
optional InternalHeader header = 39;
required string app = 1;
optional string name_space = 29;
optional string kind = 3;
optional Reference ancestor = 17;
repeated group Filter = 4 {
enum Operator {
LESS_THAN = 1;
LESS_THAN_OR_EQUAL = 2;
GREATER_THAN = 3;
GREATER_THAN_OR_EQUAL = 4;
EQUAL = 5;
IN = 6;
EXISTS = 7;
}
required Operator op = 6;
repeated Property property = 14;
}
optional string search_query = 8;
repeated group Order = 9 {
enum Direction {
ASCENDING = 1;
DESCENDING = 2;
}
required string property = 10;
optional Direction direction = 11 [default = ASCENDING];
}
enum Hint {
ORDER_FIRST = 1;
ANCESTOR_FIRST = 2;
FILTER_FIRST = 3;
}
optional Hint hint = 18;
optional int32 count = 23;
optional int32 offset = 12 [default = 0];
optional int32 limit = 16;
optional CompiledCursor compiled_cursor = 30;
optional CompiledCursor end_compiled_cursor = 31;
repeated CompositeIndex composite_index = 19;
optional bool require_perfect_plan = 20 [default = false];
optional bool keys_only = 21 [default = false];
optional Transaction transaction = 22;
optional bool compile = 25 [default = false];
optional int64 failover_ms = 26;
optional bool strong = 32;
repeated string property_name = 33;
repeated string group_by_property_name = 34;
optional bool distinct = 24;
optional int64 min_safe_time_seconds = 35;
repeated string safe_replica_name = 36;
optional bool persist_offset = 37 [default=false];
}
message CompiledQuery {
required group PrimaryScan = 1 {
optional string index_name = 2;
optional string start_key = 3;
optional bool start_inclusive = 4;
optional string end_key = 5;
optional bool end_inclusive = 6;
repeated string start_postfix_value = 22;
repeated string end_postfix_value = 23;
optional int64 end_unapplied_log_timestamp_us = 19;
}
repeated group MergeJoinScan = 7 {
required string index_name = 8;
repeated string prefix_value = 9;
optional bool value_prefix = 20 [default=false];
}
optional Index index_def = 21;
optional int32 offset = 10 [default = 0];
optional int32 limit = 11;
required bool keys_only = 12;
repeated string property_name = 24;
optional int32 distinct_infix_size = 25;
optional group EntityFilter = 13 {
optional bool distinct = 14 [default=false];
optional string kind = 17;
optional Reference ancestor = 18;
}
}
message CompiledCursor {
optional group Position = 2 {
optional string start_key = 27;
repeated group IndexValue = 29 {
optional string property = 30;
required PropertyValue value = 31;
}
optional Reference key = 32;
optional bool start_inclusive = 28 [default=true];
}
}
message Cursor {
required fixed64 cursor = 1;
optional string app = 2;
}
message Error {
enum ErrorCode {
BAD_REQUEST = 1;
CONCURRENT_TRANSACTION = 2;
INTERNAL_ERROR = 3;
NEED_INDEX = 4;
TIMEOUT = 5;
PERMISSION_DENIED = 6;
BIGTABLE_ERROR = 7;
COMMITTED_BUT_STILL_APPLYING = 8;
CAPABILITY_DISABLED = 9;
TRY_ALTERNATE_BACKEND = 10;
SAFE_TIME_TOO_OLD = 11;
}
}
message Cost {
optional int32 index_writes = 1;
optional int32 index_write_bytes = 2;
optional int32 entity_writes = 3;
optional int32 entity_write_bytes = 4;
optional group CommitCost = 5 {
optional int32 requested_entity_puts = 6;
optional int32 requested_entity_deletes = 7;
};
optional int32 approximate_storage_delta = 8;
optional int32 id_sequence_updates = 9;
}
message GetRequest {
optional InternalHeader header = 6;
repeated Reference key = 1;
optional Transaction transaction = 2;
optional int64 failover_ms = 3;
optional bool strong = 4;
optional bool allow_deferred = 5 [default=false];
}
message GetResponse {
repeated group Entity = 1 {
optional EntityProto entity = 2;
optional Reference key = 4;
optional int64 version = 3;
}
repeated Reference deferred = 5;
optional bool in_order = 6 [default=true];
}
message PutRequest {
optional InternalHeader header = 11;
repeated EntityProto entity = 1;
optional Transaction transaction = 2;
repeated CompositeIndex composite_index = 3;
optional bool trusted = 4 [default = false];
optional bool force = 7 [default = false];
optional bool mark_changes = 8 [default = false];
repeated Snapshot snapshot = 9;
enum AutoIdPolicy {
CURRENT = 0;
SEQUENTIAL = 1;
}
optional AutoIdPolicy auto_id_policy = 10 [default = CURRENT];
}
message PutResponse {
repeated Reference key = 1;
optional Cost cost = 2;
repeated int64 version = 3;
}
message TouchRequest {
optional InternalHeader header = 10;
repeated Reference key = 1;
repeated CompositeIndex composite_index = 2;
optional bool force = 3 [default = false];
repeated Snapshot snapshot = 9;
}
message TouchResponse {
optional Cost cost = 1;
}
message DeleteRequest {
optional InternalHeader header = 10;
repeated Reference key = 6;
optional Transaction transaction = 5;
optional bool trusted = 4 [default = false];
optional bool force = 7 [default = false];
optional bool mark_changes = 8 [default = false];
repeated Snapshot snapshot = 9;
}
message DeleteResponse {
optional Cost cost = 1;
repeated int64 version = 3;
}
message NextRequest {
optional InternalHeader header = 5;
required Cursor cursor = 1;
optional int32 count = 2;
optional int32 offset = 4 [default = 0];
optional bool compile = 3 [default = false];
}
message QueryResult {
optional Cursor cursor = 1;
repeated EntityProto result = 2;
optional int32 skipped_results = 7;
required bool more_results = 3;
optional bool keys_only = 4;
optional bool index_only = 9;
optional bool small_ops = 10;
optional CompiledQuery compiled_query = 5;
optional CompiledCursor compiled_cursor = 6;
repeated CompositeIndex index = 8;
repeated int64 version = 11;
}
message AllocateIdsRequest {
optional InternalHeader header = 4;
optional Reference model_key = 1;
optional int64 size = 2;
optional int64 max = 3;
repeated Reference reserve = 5;
}
message AllocateIdsResponse {
required int64 start = 1;
required int64 end = 2;
optional Cost cost = 3;
}
message CompositeIndices {
repeated CompositeIndex index = 1;
}
message AddActionsRequest {
optional InternalHeader header = 3;
required Transaction transaction = 1;
repeated Action action = 2;
}
message AddActionsResponse {
}
message BeginTransactionRequest {
optional InternalHeader header = 3;
required string app = 1;
optional bool allow_multiple_eg = 2 [default = false];
}
message CommitResponse {
optional Cost cost = 1;
repeated group Version = 3 {
required Reference root_entity_key = 4;
required int64 version = 5;
}
}

View File

@@ -1,58 +0,0 @@
// Copyright 2014 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
package internal
import (
"io"
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"
)
func TestInstallingHealthChecker(t *testing.T) {
try := func(desc string, mux *http.ServeMux, wantCode int, wantBody string) {
installHealthChecker(mux)
srv := httptest.NewServer(mux)
defer srv.Close()
resp, err := http.Get(srv.URL + "/_ah/health")
if err != nil {
t.Errorf("%s: http.Get: %v", desc, err)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Errorf("%s: reading body: %v", desc, err)
return
}
if resp.StatusCode != wantCode {
t.Errorf("%s: got HTTP %d, want %d", desc, resp.StatusCode, wantCode)
return
}
if wantBody != "" && string(body) != wantBody {
t.Errorf("%s: got HTTP body %q, want %q", desc, body, wantBody)
return
}
}
// If there's no handlers, or only a root handler, a health checker should be installed.
try("empty mux", http.NewServeMux(), 200, "ok")
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "root handler")
})
try("mux with root handler", mux, 200, "ok")
// If there's a custom health check handler, one should not be installed.
mux = http.NewServeMux()
mux.HandleFunc("/_ah/health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(418)
io.WriteString(w, "I'm short and stout!")
})
try("mux with custom health checker", mux, 418, "I'm short and stout!")
}

View File

@@ -1,150 +0,0 @@
syntax = "proto2";
option go_package = "log";
package appengine;
message LogServiceError {
enum ErrorCode {
OK = 0;
INVALID_REQUEST = 1;
STORAGE_ERROR = 2;
}
}
message UserAppLogLine {
required int64 timestamp_usec = 1;
required int64 level = 2;
required string message = 3;
}
message UserAppLogGroup {
repeated UserAppLogLine log_line = 2;
}
message FlushRequest {
optional bytes logs = 1;
}
message SetStatusRequest {
required string status = 1;
}
message LogOffset {
optional bytes request_id = 1;
}
message LogLine {
required int64 time = 1;
required int32 level = 2;
required string log_message = 3;
}
message RequestLog {
required string app_id = 1;
optional string module_id = 37 [default="default"];
required string version_id = 2;
required bytes request_id = 3;
optional LogOffset offset = 35;
required string ip = 4;
optional string nickname = 5;
required int64 start_time = 6;
required int64 end_time = 7;
required int64 latency = 8;
required int64 mcycles = 9;
required string method = 10;
required string resource = 11;
required string http_version = 12;
required int32 status = 13;
required int64 response_size = 14;
optional string referrer = 15;
optional string user_agent = 16;
required string url_map_entry = 17;
required string combined = 18;
optional int64 api_mcycles = 19;
optional string host = 20;
optional double cost = 21;
optional string task_queue_name = 22;
optional string task_name = 23;
optional bool was_loading_request = 24;
optional int64 pending_time = 25;
optional int32 replica_index = 26 [default = -1];
optional bool finished = 27 [default = true];
optional bytes clone_key = 28;
repeated LogLine line = 29;
optional bool lines_incomplete = 36;
optional bytes app_engine_release = 38;
optional int32 exit_reason = 30;
optional bool was_throttled_for_time = 31;
optional bool was_throttled_for_requests = 32;
optional int64 throttled_time = 33;
optional bytes server_name = 34;
}
message LogModuleVersion {
optional string module_id = 1 [default="default"];
optional string version_id = 2;
}
message LogReadRequest {
required string app_id = 1;
repeated string version_id = 2;
repeated LogModuleVersion module_version = 19;
optional int64 start_time = 3;
optional int64 end_time = 4;
optional LogOffset offset = 5;
repeated bytes request_id = 6;
optional int32 minimum_log_level = 7;
optional bool include_incomplete = 8;
optional int64 count = 9;
optional string combined_log_regex = 14;
optional string host_regex = 15;
optional int32 replica_index = 16;
optional bool include_app_logs = 10;
optional int32 app_logs_per_request = 17;
optional bool include_host = 11;
optional bool include_all = 12;
optional bool cache_iterator = 13;
optional int32 num_shards = 18;
}
message LogReadResponse {
repeated RequestLog log = 1;
optional LogOffset offset = 2;
optional int64 last_end_time = 3;
}
message LogUsageRecord {
optional string version_id = 1;
optional int32 start_time = 2;
optional int32 end_time = 3;
optional int64 count = 4;
optional int64 total_size = 5;
optional int32 records = 6;
}
message LogUsageRequest {
required string app_id = 1;
repeated string version_id = 2;
optional int32 start_time = 3;
optional int32 end_time = 4;
optional uint32 resolution_hours = 5 [default = 1];
optional bool combine_versions = 6;
optional int32 usage_version = 7;
optional bool versions_only = 8;
}
message LogUsageResponse {
repeated LogUsageRecord usage = 1;
optional LogUsageRecord summary = 2;
}

View File

@@ -1,58 +0,0 @@
// Copyright 2014 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// +build !appengine
package internal
import (
"sync"
"testing"
"time"
netcontext "golang.org/x/net/context"
basepb "google.golang.org/appengine/internal/base"
)
func TestDialLimit(t *testing.T) {
// Fill up semaphore with false acquisitions to permit only two TCP connections at a time.
// We don't replace limitSem because that results in a data race when net/http lazily closes connections.
nFake := cap(limitSem) - 2
for i := 0; i < nFake; i++ {
limitSem <- 1
}
defer func() {
for i := 0; i < nFake; i++ {
<-limitSem
}
}()
f, c, cleanup := setup() // setup is in api_test.go
defer cleanup()
f.hang = make(chan int)
// If we make two RunSlowly RPCs (which will wait for f.hang to be strobed),
// then the simple Non200 RPC should hang.
var wg sync.WaitGroup
wg.Add(2)
for i := 0; i < 2; i++ {
go func() {
defer wg.Done()
Call(toContext(c), "errors", "RunSlowly", &basepb.VoidProto{}, &basepb.VoidProto{})
}()
}
time.Sleep(50 * time.Millisecond) // let those two RPCs start
ctx, _ := netcontext.WithTimeout(toContext(c), 50*time.Millisecond)
err := Call(ctx, "errors", "Non200", &basepb.VoidProto{}, &basepb.VoidProto{})
if err != errTimeout {
t.Errorf("Non200 RPC returned with err %v, want errTimeout", err)
}
// Drain the two RunSlowly calls.
f.hang <- 1
f.hang <- 1
wg.Wait()
}

View File

@@ -1,40 +0,0 @@
#!/bin/bash -e
#
# This script rebuilds the generated code for the protocol buffers.
# To run this you will need protoc and goprotobuf installed;
# see https://github.com/golang/protobuf for instructions.
PKG=google.golang.org/appengine
function die() {
echo 1>&2 $*
exit 1
}
# Sanity check that the right tools are accessible.
for tool in go protoc protoc-gen-go; do
q=$(which $tool) || die "didn't find $tool"
echo 1>&2 "$tool: $q"
done
echo -n 1>&2 "finding package dir... "
pkgdir=$(go list -f '{{.Dir}}' $PKG)
echo 1>&2 $pkgdir
base=$(echo $pkgdir | sed "s,/$PKG\$,,")
echo 1>&2 "base: $base"
cd $base
# Run protoc once per package.
for dir in $(find $PKG/internal -name '*.proto' | xargs dirname | sort | uniq); do
echo 1>&2 "* $dir"
protoc --go_out=. $dir/*.proto
done
for f in $(find $PKG/internal -name '*.pb.go'); do
# Remove proto.RegisterEnum calls.
# These cause duplicate registration panics when these packages
# are used on classic App Engine. proto.RegisterEnum only affects
# parsing the text format; we don't care about that.
# https://code.google.com/p/googleappengine/issues/detail?id=11670#c17
sed -i '/proto.RegisterEnum/d' $f
done

View File

@@ -1,44 +0,0 @@
syntax = "proto2";
option go_package = "remote_api";
package remote_api;
message Request {
required string service_name = 2;
required string method = 3;
required bytes request = 4;
optional string request_id = 5;
}
message ApplicationError {
required int32 code = 1;
required string detail = 2;
}
message RpcError {
enum ErrorCode {
UNKNOWN = 0;
CALL_NOT_FOUND = 1;
PARSE_ERROR = 2;
SECURITY_VIOLATION = 3;
OVER_QUOTA = 4;
REQUEST_TOO_LARGE = 5;
CAPABILITY_DISABLED = 6;
FEATURE_DISABLED = 7;
BAD_REQUEST = 8;
RESPONSE_TOO_LARGE = 9;
CANCELLED = 10;
REPLAY_ERROR = 11;
DEADLINE_EXCEEDED = 12;
}
required int32 code = 1;
optional string detail = 2;
}
message Response {
optional bytes response = 1;
optional bytes exception = 2;
optional ApplicationError application_error = 3;
optional bytes java_exception = 4;
optional RpcError rpc_error = 5;
}

View File

@@ -1,64 +0,0 @@
syntax = "proto2";
option go_package = "urlfetch";
package appengine;
message URLFetchServiceError {
enum ErrorCode {
OK = 0;
INVALID_URL = 1;
FETCH_ERROR = 2;
UNSPECIFIED_ERROR = 3;
RESPONSE_TOO_LARGE = 4;
DEADLINE_EXCEEDED = 5;
SSL_CERTIFICATE_ERROR = 6;
DNS_ERROR = 7;
CLOSED = 8;
INTERNAL_TRANSIENT_ERROR = 9;
TOO_MANY_REDIRECTS = 10;
MALFORMED_REPLY = 11;
CONNECTION_ERROR = 12;
}
}
message URLFetchRequest {
enum RequestMethod {
GET = 1;
POST = 2;
HEAD = 3;
PUT = 4;
DELETE = 5;
PATCH = 6;
}
required RequestMethod Method = 1;
required string Url = 2;
repeated group Header = 3 {
required string Key = 4;
required string Value = 5;
}
optional bytes Payload = 6 [ctype=CORD];
optional bool FollowRedirects = 7 [default=true];
optional double Deadline = 8;
optional bool MustValidateServerCertificate = 9 [default=true];
}
message URLFetchResponse {
optional bytes Content = 1;
required int32 StatusCode = 2;
repeated group Header = 3 {
required string Key = 4;
required string Value = 5;
}
optional bool ContentWasTruncated = 6 [default=false];
optional int64 ExternalBytesSent = 7;
optional int64 ExternalBytesReceived = 8;
optional string FinalUrl = 9;
optional int64 ApiCpuMilliseconds = 10 [default=0];
optional int64 ApiBytesSent = 11 [default=0];
optional int64 ApiBytesReceived = 12 [default=0];
}