示例#1
0
// NewRemoteContext returns a context that gives access to the production
// APIs for the application at the given host. All communication will be
// performed over SSL unless the host is localhost.
func NewRemoteContext(host string, client *http.Client) (context.Context, error) {
	// Add an appcfg header to outgoing requests.
	t := client.Transport
	if t == nil {
		t = http.DefaultTransport
	}
	client.Transport = &headerAddingRoundTripper{t}

	url := url.URL{
		Scheme: "https",
		Host:   host,
		Path:   "/_ah/remote_api",
	}
	if host == "localhost" || strings.HasPrefix(host, "localhost:") {
		url.Scheme = "http"
	}
	u := url.String()
	appID, err := getAppID(client, u)
	if err != nil {
		return nil, fmt.Errorf("unable to contact server: %v", err)
	}
	rc := &remoteContext{
		client: client,
		url:    u,
	}
	ctx := internal.WithCallOverride(context.Background(), rc.call)
	ctx = internal.WithLogOverride(ctx, rc.logf)
	ctx = internal.WithAppIDOverride(ctx, appID)
	return ctx, nil
}
示例#2
0
// NewRequest returns an *http.Request associated with this instance.
func (i *instance) NewRequest(method, urlStr string, body io.Reader) (*http.Request, error) {
	req, err := http.NewRequest(method, urlStr, body)
	if err != nil {
		return nil, err
	}

	// Associate this request.
	release := internal.RegisterTestRequest(req, i.apiURL, func(ctx context.Context) context.Context {
		ctx = internal.WithAppIDOverride(ctx, "dev~"+i.appID)
		return ctx
	})
	i.relFuncs = append(i.relFuncs, release)

	return req, nil
}
示例#3
0
func TestIncompleteKeyWithParent(t *testing.T) {
	c := internal.WithAppIDOverride(context.Background(), "s~some-app")

	// fadduh is a complete key.
	fadduh := NewKey(c, "Person", "", 1, nil)
	if fadduh.Incomplete() {
		t.Fatalf("fadduh is incomplete")
	}

	// robert is an incomplete key with fadduh as a parent.
	robert := NewIncompleteKey(c, "Person", fadduh)
	if !robert.Incomplete() {
		t.Fatalf("robert is complete")
	}

	// Both should be valid keys.
	if !fadduh.valid() {
		t.Errorf("fadduh is invalid: %v", fadduh)
	}
	if !robert.valid() {
		t.Errorf("robert is invalid: %v", robert)
	}
}
示例#4
0
func TestQueryToProto(t *testing.T) {
	// The context is required to make Keys for the test cases.
	var got *pb.Query
	NoErr := errors.New("No error")
	c := aetesting.FakeSingleContext(t, "datastore_v3", "RunQuery", func(in *pb.Query, out *pb.QueryResult) error {
		got = in
		return NoErr // return a non-nil error so Run doesn't keep going.
	})
	c = internal.WithAppIDOverride(c, "dev~fake-app")

	testCases := []struct {
		desc  string
		query *Query
		want  *pb.Query
		err   string
	}{
		{
			desc:  "empty",
			query: NewQuery(""),
			want:  &pb.Query{},
		},
		{
			desc:  "standard query",
			query: NewQuery("kind").Order("-I").Filter("I >", 17).Filter("U =", "Dave").Limit(7).Offset(42),
			want: &pb.Query{
				Kind: proto.String("kind"),
				Filter: []*pb.Query_Filter{
					{
						Op: pb.Query_Filter_GREATER_THAN.Enum(),
						Property: []*pb.Property{
							{
								Name:     proto.String("I"),
								Value:    &pb.PropertyValue{Int64Value: proto.Int64(17)},
								Multiple: proto.Bool(false),
							},
						},
					},
					{
						Op: pb.Query_Filter_EQUAL.Enum(),
						Property: []*pb.Property{
							{
								Name:     proto.String("U"),
								Value:    &pb.PropertyValue{StringValue: proto.String("Dave")},
								Multiple: proto.Bool(false),
							},
						},
					},
				},
				Order: []*pb.Query_Order{
					{
						Property:  proto.String("I"),
						Direction: pb.Query_Order_DESCENDING.Enum(),
					},
				},
				Limit:  proto.Int32(7),
				Offset: proto.Int32(42),
			},
		},
		{
			desc:  "ancestor",
			query: NewQuery("").Ancestor(NewKey(c, "kind", "Mummy", 0, nil)),
			want: &pb.Query{
				Ancestor: &pb.Reference{
					App: proto.String("dev~fake-app"),
					Path: &pb.Path{
						Element: []*pb.Path_Element{{Type: proto.String("kind"), Name: proto.String("Mummy")}},
					},
				},
			},
		},
		{
			desc:  "projection",
			query: NewQuery("").Project("A", "B"),
			want: &pb.Query{
				PropertyName: []string{"A", "B"},
			},
		},
		{
			desc:  "projection with distinct",
			query: NewQuery("").Project("A", "B").Distinct(),
			want: &pb.Query{
				PropertyName:        []string{"A", "B"},
				GroupByPropertyName: []string{"A", "B"},
			},
		},
		{
			desc:  "keys only",
			query: NewQuery("").KeysOnly(),
			want: &pb.Query{
				KeysOnly:           proto.Bool(true),
				RequirePerfectPlan: proto.Bool(true),
			},
		},
		{
			desc:  "empty filter",
			query: NewQuery("kind").Filter("=", 17),
			err:   "empty query filter field nam",
		},
		{
			desc:  "bad filter type",
			query: NewQuery("kind").Filter("M =", map[string]bool{}),
			err:   "bad query filter value type",
		},
		{
			desc:  "bad filter operator",
			query: NewQuery("kind").Filter("I <<=", 17),
			err:   `invalid operator "<<=" in filter "I <<="`,
		},
		{
			desc:  "empty order",
			query: NewQuery("kind").Order(""),
			err:   "empty order",
		},
		{
			desc:  "bad order direction",
			query: NewQuery("kind").Order("+I"),
			err:   `invalid order: "+I`,
		},
	}

	for _, tt := range testCases {
		got = nil
		if _, err := tt.query.Run(c).Next(nil); err != NoErr {
			if tt.err == "" || !strings.Contains(err.Error(), tt.err) {
				t.Errorf("%s: error %v, want %q", tt.desc, err, tt.err)
			}
			continue
		}
		if tt.err != "" {
			t.Errorf("%s: no error, want %q", tt.desc, tt.err)
			continue
		}
		// Fields that are common to all protos.
		tt.want.App = proto.String("dev~fake-app")
		tt.want.Compile = proto.Bool(true)
		if !proto.Equal(got, tt.want) {
			t.Errorf("%s:\ngot  %v\nwant %v", tt.desc, got, tt.want)
		}
	}
}
示例#5
0
func TestSimpleQuery(t *testing.T) {
	struct1 := Gopher{Name: "George", Height: 32}
	struct2 := Gopher{Name: "Rufus"}
	pList1 := PropertyList{
		{
			Name:  "Name",
			Value: "George",
		},
		{
			Name:  "Height",
			Value: int64(32),
		},
	}
	pList2 := PropertyList{
		{
			Name:  "Name",
			Value: "Rufus",
		},
	}
	pMap1 := PropertyMap{
		"Name": Property{
			Name:  "Name",
			Value: "George",
		},
		"Height": Property{
			Name:  "Height",
			Value: int64(32),
		},
	}
	pMap2 := PropertyMap{
		"Name": Property{
			Name:  "Name",
			Value: "Rufus",
		},
	}

	testCases := []struct {
		dst  interface{}
		want interface{}
	}{
		// The destination must have type *[]P, *[]S or *[]*S, for some non-interface
		// type P such that *P implements PropertyLoadSaver, or for some struct type S.
		{new([]Gopher), &[]Gopher{struct1, struct2}},
		{new([]*Gopher), &[]*Gopher{&struct1, &struct2}},
		{new([]PropertyList), &[]PropertyList{pList1, pList2}},
		{new([]PropertyMap), &[]PropertyMap{pMap1, pMap2}},

		// Any other destination type is invalid.
		{0, nil},
		{Gopher{}, nil},
		{PropertyList{}, nil},
		{PropertyMap{}, nil},
		{[]int{}, nil},
		{[]Gopher{}, nil},
		{[]PropertyList{}, nil},
		{new(int), nil},
		{new(Gopher), nil},
		{new(PropertyList), nil}, // This is a special case.
		{new(PropertyMap), nil},
		{new([]int), nil},
		{new([]map[int]int), nil},
		{new([]map[string]Property), nil},
		{new([]map[string]interface{}), nil},
		{new([]*int), nil},
		{new([]*map[int]int), nil},
		{new([]*map[string]Property), nil},
		{new([]*map[string]interface{}), nil},
		{new([]**Gopher), nil},
		{new([]*PropertyList), nil},
		{new([]*PropertyMap), nil},
	}
	for _, tc := range testCases {
		nCall := 0
		c := aetesting.FakeSingleContext(t, "datastore_v3", "RunQuery", func(in *pb.Query, out *pb.QueryResult) error {
			nCall++
			return fakeRunQuery(in, out)
		})
		c = internal.WithAppIDOverride(c, "dev~fake-app")

		var (
			expectedErr   error
			expectedNCall int
		)
		if tc.want == nil {
			expectedErr = ErrInvalidEntityType
		} else {
			expectedNCall = 1
		}
		keys, err := NewQuery("Gopher").GetAll(c, tc.dst)
		if err != expectedErr {
			t.Errorf("dst type %T: got error [%v], want [%v]", tc.dst, err, expectedErr)
			continue
		}
		if nCall != expectedNCall {
			t.Errorf("dst type %T: Context.Call was called an incorrect number of times: got %d want %d", tc.dst, nCall, expectedNCall)
			continue
		}
		if err != nil {
			continue
		}

		key1 := NewKey(c, "Gopher", "", 6, nil)
		expectedKeys := []*Key{
			key1,
			NewKey(c, "Gopher", "", 8, key1),
		}
		if l1, l2 := len(keys), len(expectedKeys); l1 != l2 {
			t.Errorf("dst type %T: got %d keys, want %d keys", tc.dst, l1, l2)
			continue
		}
		for i, key := range keys {
			if key.AppID() != "s~test-app" {
				t.Errorf(`dst type %T: Key #%d's AppID = %q, want "s~test-app"`, tc.dst, i, key.AppID())
				continue
			}
			if !keysEqual(key, expectedKeys[i]) {
				t.Errorf("dst type %T: got key #%d %v, want %v", tc.dst, i, key, expectedKeys[i])
				continue
			}
		}

		if !reflect.DeepEqual(tc.dst, tc.want) {
			t.Errorf("dst type %T: Entities got %+v, want %+v", tc.dst, tc.dst, tc.want)
			continue
		}
	}
}