1// Copyright 2011 Google Inc. All rights reserved. 2// Use of this source code is governed by the Apache 2.0 3// license that can be found in the LICENSE file. 4 5// Package aetesting provides utilities for testing App Engine packages. 6// This is not for testing user applications. 7package aetesting 8 9import ( 10 "fmt" 11 "net/http" 12 "reflect" 13 "testing" 14 15 "github.com/golang/protobuf/proto" 16 "golang.org/x/net/context" 17 18 "google.golang.org/appengine/internal" 19) 20 21// FakeSingleContext returns a context whose Call invocations will be serviced 22// by f, which should be a function that has two arguments of the input and output 23// protocol buffer type, and one error return. 24func FakeSingleContext(t *testing.T, service, method string, f interface{}) context.Context { 25 fv := reflect.ValueOf(f) 26 if fv.Kind() != reflect.Func { 27 t.Fatal("not a function") 28 } 29 ft := fv.Type() 30 if ft.NumIn() != 2 || ft.NumOut() != 1 { 31 t.Fatalf("f has %d in and %d out, want 2 in and 1 out", ft.NumIn(), ft.NumOut()) 32 } 33 for i := 0; i < 2; i++ { 34 at := ft.In(i) 35 if !at.Implements(protoMessageType) { 36 t.Fatalf("arg %d does not implement proto.Message", i) 37 } 38 } 39 if ft.Out(0) != errorType { 40 t.Fatalf("f's return is %v, want error", ft.Out(0)) 41 } 42 s := &single{ 43 t: t, 44 service: service, 45 method: method, 46 f: fv, 47 } 48 return internal.WithCallOverride(internal.ContextForTesting(&http.Request{}), s.call) 49} 50 51var ( 52 protoMessageType = reflect.TypeOf((*proto.Message)(nil)).Elem() 53 errorType = reflect.TypeOf((*error)(nil)).Elem() 54) 55 56type single struct { 57 t *testing.T 58 service, method string 59 f reflect.Value 60} 61 62func (s *single) call(ctx context.Context, service, method string, in, out proto.Message) error { 63 if service == "__go__" { 64 if method == "GetNamespace" { 65 return nil // always yield an empty namespace 66 } 67 return fmt.Errorf("Unknown API call /%s.%s", service, method) 68 } 69 if service != s.service || method != s.method { 70 s.t.Fatalf("Unexpected call to /%s.%s", service, method) 71 } 72 ins := []reflect.Value{ 73 reflect.ValueOf(in), 74 reflect.ValueOf(out), 75 } 76 outs := s.f.Call(ins) 77 if outs[0].IsNil() { 78 return nil 79 } 80 return outs[0].Interface().(error) 81} 82