func setNamespace(context appengine.Context, r *http.Request) (c appengine.Context, err error) { if n := r.Header.Get("User"); n != "" { if c, err = appengine.Namespace(context, n); err != nil { return nil, err } } else { if c, err = appengine.Namespace(context, DEFAULT_CONTEXT); err != nil { return nil, err } } return c, nil }
func readBothNamespaces(w http.ResponseWriter, r *http.Request, m map[string]interface{}) { lg, b := loghttp.BuffLoggerUniversal(w, r) _ = b var c1, c2 int64 var s1, s2 string var err error var reset bool = false p := r.FormValue("reset") if p != "" { reset = true } c := appengine.NewContext(r) c1, err = agnosticReadReset(c, reset) lg(err) { c, err = appengine.Namespace(c, altNamespace) lg(err) c2, err = agnosticReadReset(c, reset) lg(err) } s1 = fmt.Sprintf("%v", c1) s2 = fmt.Sprintf("%v", c2) io.WriteString(w, "|"+s1+"| |"+s2+"|") if reset { io.WriteString(w, " and reset") } }
func queuePush(w http.ResponseWriter, r *http.Request, mx map[string]interface{}) { lg, b := loghttp.BuffLoggerUniversal(w, r) _ = b c := appengine.NewContext(r) m := map[string][]string{"counter_name": []string{nscStringKey}} t := taskqueue.NewPOSTTask("/_ah/namespaced-counters/queue-pop", m) taskqueue.Add(c, t, "") c, err := appengine.Namespace(c, altNamespace) lg(err) taskqueue.Add(c, t, "") io.WriteString(w, "tasks enqueued\n") io.WriteString(w, "\ncounter values now: \n") readBothNamespaces(w, r, mx) io.WriteString(w, "\n\n...sleeping... \n") time.Sleep(time.Duration(400) * time.Millisecond) readBothNamespaces(w, r, mx) }
func readBothNamespaces(w http.ResponseWriter, r *http.Request) { var c1, c2 int64 var s1, s2 string var err error var reset bool = false p := r.FormValue("reset") if p != "" { reset = true } c := appengine.NewContext(r) c1, err = agnosticReadReset(c, reset) util_err.Err_log(err) { c, err = appengine.Namespace(c, altNamespace) util_err.Err_log(err) c2, err = agnosticReadReset(c, reset) util_err.Err_log(err) } s1 = fmt.Sprintf("%v", c1) s2 = fmt.Sprintf("%v", c2) io.WriteString(w, "|"+s1+"| |"+s2+"|") if reset { io.WriteString(w, " and reset") } }
// getCachedCerts fetches public certificates info from DefaultCertURI and // caches it for the duration specified in Age header of a response. func getCachedCerts(c Context) (*certsList, error) { namespacedContext, err := appengine.Namespace(c, certNamespace) if err != nil { return nil, err } var certs *certsList _, err = memcache.JSON.Get(namespacedContext, DefaultCertURI, &certs) if err == nil { return certs, nil } // Cache miss or server error. // If any error other than cache miss, it's proably not a good time // to use memcache. var cacheResults = err == memcache.ErrCacheMiss if !cacheResults { c.Debugf(err.Error()) } c.Debugf("Fetching provider certs from: %s", DefaultCertURI) resp, err := newHTTPClient(c).Get(DefaultCertURI) if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return nil, errors.New("Could not reach Cert URI or bad response.") } certBytes, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, err } // Restore r.Body resp.Body = ioutil.NopCloser(bytes.NewBuffer(certBytes)) err = json.Unmarshal(certBytes, &certs) if err != nil { return nil, err } if cacheResults { expiration := getCertExpirationTime(resp.Header) if expiration > 0 { item := &memcache.Item{ Key: DefaultCertURI, Value: certBytes, Expiration: expiration, } err = memcache.Set(namespacedContext, item) if err != nil { c.Errorf("Error adding Certs to memcache: %v", err) } } } return certs, nil }
// Namespace returns a replacement context that operates within the given namespace. func (c *cachingContext) Namespace(name string) (Context, error) { nc, err := appengine.Namespace(c, name) if err != nil { return nil, err } return newCachingContext(nc, c.r), nil }
// AppengineContextProvider provides an injectable and namespaced // instance of appengine.Context func AppengineContextProvider(c martini.Context, req *http.Request) { gae := appengine.NewContext(req) namespace := appengine.ModuleName(gae) context, err := appengine.Namespace(gae, namespace) if err != nil { panic(err) } c.Map(context) }
func (d *Driver) Namespace(namespace string) *Driver { var err error d.ctx, err = appengine.Namespace(d.ctx, namespace) d.namespace = namespace if err != nil { panic(err) } return d }
// getCachedCerts fetches public certificates info from DefaultCertUri and // caches it for the duration specified in Age header of a response. func getCachedCerts(c Context) (*certsList, error) { namespacedContext, err := appengine.Namespace(c, certNamespace) if err != nil { return nil, err } var certs *certsList _, err = memcache.JSON.Get(namespacedContext, DefaultCertUri, &certs) if err == nil { return certs, nil } // Cache miss or server error. // If any error other than cache miss, it's proably not a good time // to use memcache. var cacheResults = err == memcache.ErrCacheMiss if !cacheResults { c.Debugf(err.Error()) } client := urlfetch.Client(c) resp, err := client.Get(DefaultCertUri) if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode != 200 { return nil, errors.New("Could not reach Cert URI") } certBytes, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, err } err = json.Unmarshal(certBytes, &certs) if err != nil { return nil, err } if cacheResults { expiration := getCertExpirationTime(resp.Header) if expiration > 0 { item := &memcache.Item{ Key: DefaultCertUri, Value: certBytes, Expiration: expiration, } err = memcache.Set(namespacedContext, item) if err != nil { c.Errorf("Error adding Certs to memcache: %v", err) } } } return certs, nil }
// Context returns a namespaced context for this dashboard, or panics if it // fails to create a new context. func (d *Dashboard) Context(c appengine.Context) appengine.Context { if d.Namespace == "" { return c } n, err := appengine.Namespace(c, d.Namespace) if err != nil { panic(err) } return n }
// Stat returns the BlobInfo for a provided blobKey. If no blob was found for // that key, Stat returns datastore.ErrNoSuchEntity. func Stat(c appengine.Context, blobKey appengine.BlobKey) (*BlobInfo, error) { c, _ = appengine.Namespace(c, "") // Blobstore is always in the empty string namespace dskey := datastore.NewKey(c, blobInfoKind, string(blobKey), 0, nil) bi := &BlobInfo{ BlobKey: blobKey, } if err := datastore.Get(c, dskey, bi); err != nil && !isErrFieldMismatch(err) { return nil, err } return bi, nil }
func ResolveGaeContext() gin.HandlerFunc { return func(c *gin.Context) { gaeRootCtx := appengine.NewContext(c.Request) c.Set(gaeRootCtxKey, gaeRootCtx) namespace := "" if productionDomain := os.Getenv("PRODUCTION_DOMAIN"); productionDomain != "" { if strings.HasPrefix(productionDomain, ".") == false { productionDomain = fmt.Sprintf(".%s", productionDomain) } lastIndex := strings.LastIndex(c.Request.Host, productionDomain) if lastIndex > -1 { namespace = strings.Replace(c.Request.Host, productionDomain, "", lastIndex) } } else if devNamespace := os.Getenv("DEV_NAMESPACE"); devNamespace != "" { namespace = devNamespace } // Still no namespace. Maybe the request is to the appspot domain if namespace == "" { requestHost := convertDots(c.Request.Host) requestHost = strings.Replace(requestHost, "master.", "", 1) hostName, _ := appengine.ModuleHostname(gaeRootCtx, appengine.ModuleName(gaeRootCtx), "master", "") hostName = convertDots(hostName) hostName = strings.Replace(hostName, "master.", "", 1) hostName = fmt.Sprintf(".%s", hostName) lastIndex := strings.LastIndex(requestHost, hostName) if lastIndex > -1 { namespace = strings.Replace(requestHost, hostName, "", lastIndex) } } // Still no namespace? Last resort is a custom header if namespace == "" { namespace = c.Request.Header.Get(NamespaceHeader) } gaeRootCtx.Debugf("Using namespace: \"%s\"", namespace) nameSpacedGaeCtx, err := appengine.Namespace(gaeRootCtx, namespace) if err != nil { GetGaeRootContext(c).Errorf("Error creating namespace: %v", err) c.AbortWithError(500, err) return } c.Set(gaeCtxKey, nameSpacedGaeCtx) c.Set(namespaceKey, namespace) } }
// Context returns a namespaced context for this dashboard, or panics if it // fails to create a new context. func (d *Dashboard) Context(c appengine.Context) appengine.Context { // No namespace needed for the original Go dashboard. if d.Name == "Go" { return c } n, err := appengine.Namespace(c, d.Name) if err != nil { panic(err) } return n }
func AppengineContextProvider(c martini.Context, request *http.Request) { gae := appengine.NewContext(request) namespace := appengine.ModuleName(gae) context, err := appengine.Namespace(gae, namespace) if err != nil { panic(fmt.Sprintf("Could not create GAE context: %v", err)) } c.MapTo(context, (*appengine.Context)(nil)) }
func TestDatastoreFixture(t *testing.T) { filepath := mkTempfile(`[{ "_kind": "FixtureKind", "_key": "key1", "IntValue": 10, "FloatValue": 2.4, "BoolValue": true, "StringValue": "foobar", "BytesValue": "[]bytesfoobar", "DateTimeValue": "2014-01-02T14:02:50Z", "DateValue": "2014-01-02", "Children": [{ "_kind": "FixtureKindChildren", "_key": "keyc1", "Foo": "bar" }] },{ "_kind": "FixtureKind", "_key": "key1", "_ns": "ns1", "StringValue": "withns1" } ]`) assert := wcg.NewAssert(t) RunTestServer(func(ts *TestServer) { var fk FixtureKind var fkc1 FixtureKindChildren DatastoreFixture(ts.Context, filepath, nil) key := datastore.NewKey(ts.Context, "FixtureKind", "key1", 0, nil) keyc1 := datastore.NewKey(ts.Context, "FixtureKindChildren", "keyc1", 0, key) assert.Nil(datastore.Get(ts.Context, key, &fk), "datastore.Get('key1') ") assert.Nil(datastore.Get(ts.Context, keyc1, &fkc1), "datastore.Get('keyc1') ") assert.EqInt(10, fk.IntValue, "IntValue should be 10") assert.EqFloat32(2.4, fk.FloatValue, "FloatValue should be 2.4") assert.EqStr("foobar", fk.StringValue, "StringValue should be 'foobar'") assert.EqStr("bytesfoobar", string(fk.BytesValue), "BytesValue should be 'foobar'") assert.EqTime(time.Date(2014, 01, 02, 14, 02, 50, 0, time.UTC), fk.DateTimeValue, "DateTimeValue should be 2014-01-02T14:02:50Z") assert.EqTime(time.Date(2014, 01, 02, 0, 0, 0, 0, time.UTC), fk.DateValue, "DateTimeValue should be 2014-01-02T00:00:00Z") // namespace ns1, _ := appengine.Namespace(ts.Context, "ns1") key = datastore.NewKey(ns1, "FixtureKind", "key1", 0, nil) assert.Nil(datastore.Get(ns1, key, &fk), "datastore.Get('key1') /w ns1") assert.EqStr("withns1", fk.StringValue, "StringValue should be 'withns1'") }) }
func TestverifySignedJWT(t *testing.T) { r, _, closer := newTestRequest(t, "GET", "/", nil) defer closer() nc, err := appengine.Namespace(appengine.NewContext(r), certNamespace) if err != nil { t.Fatal(err) } item := &memcache.Item{Key: DefaultCertURI, Value: []byte(googCerts)} if err := memcache.Set(nc, item); err != nil { t.Fatal(err) } tts := []struct { token string now time.Time want *signedJWT }{ {jwtValidTokenString, jwtValidTokenTime, &jwtValidTokenObject}, {jwtValidTokenString, jwtValidTokenTime.Add(time.Hour * 24), nil}, {jwtValidTokenString, jwtValidTokenTime.Add(-time.Hour * 24), nil}, {jwtInvalidKeyToken, jwtValidTokenTime, nil}, {jwtInvalidAlgToken, jwtValidTokenTime, nil}, {"invalid.token", jwtValidTokenTime, nil}, {"another.invalid.token", jwtValidTokenTime, nil}, } ec := NewContext(r) for i, tt := range tts { jwt, err := verifySignedJWT(ec, tt.token, tt.now.Unix()) switch { case err != nil && tt.want != nil: t.Errorf("%d: verifySignedJWT(%q, %d) = %v; want %#v", i, tt.token, tt.now.Unix(), err, tt.want) case err == nil && tt.want == nil: t.Errorf("%d: verifySignedJWT(%q, %d) = %#v; want error", i, tt.token, tt.now.Unix(), jwt) case err == nil && tt.want != nil: if !reflect.DeepEqual(jwt, tt.want) { t.Errorf("%d: verifySignedJWT(%q, %d) = %v; want %#v", i, tt.token, tt.now.Unix(), jwt, tt.want) } } } }
func TestGetCachedCertsCacheHit(t *testing.T) { origTransport := httpTransportFactory defer func() { httpTransportFactory = origTransport }() httpTransportFactory = func(c appengine.Context) http.RoundTripper { return newTestRoundTripper() } req, _, closer := newTestRequest(t, "GET", "/", nil) defer closer() nc, err := appengine.Namespace(appengine.NewContext(req), certNamespace) if err != nil { t.Fatal(err) } tts := []struct { cacheValue string want *certsList }{ {"", nil}, {"{}", &certsList{}}, {`{"keyvalues": [{}]}`, &certsList{[]*certInfo{{}}}}, {`{"keyvalues": [ {"algorithm": "RS256", "exponent": "123", "keyid": "some-id", "modulus": "123"} ]}`, &certsList{[]*certInfo{{"RS256", "123", "some-id", "123"}}}}, } ec := NewContext(req) for i, tt := range tts { item := &memcache.Item{Key: DefaultCertURI, Value: []byte(tt.cacheValue)} if err := memcache.Set(nc, item); err != nil { t.Fatal(err) } out, err := getCachedCerts(ec) switch { case err != nil && tt.want != nil: t.Errorf("%d: getCachedCerts() error %v", i, err) case err == nil && tt.want == nil: t.Errorf("%d: getCachedCerts() = %#v; want error", i, out) case err == nil && tt.want != nil && !reflect.DeepEqual(out, tt.want): t.Errorf("getCachedCerts() = %#+v (%T); want %#+v (%T)", out, out, tt.want, tt.want) } } }
func handleRequest(writer http.ResponseWriter, request *http.Request) { context := appengine.NewContext(request) user := user.Current(context) namespaceContext, _ := appengine.Namespace(context, user.ID) if request.Method == "GET" { handleGet(writer, request, namespaceContext) } else if request.Method == "POST" { handlePost(writer, request, namespaceContext) } else if request.Method == "PUT" { handlePut(writer, request, namespaceContext) } else if request.Method == "DELETE" { handleDelete(writer, request, namespaceContext) } else { http.Error(writer, "Invalid request method.", 405) } }
func incrementBothNamespaces(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) err := agnosticIncrement(c) util_err.Err_log(err) { c, err := appengine.Namespace(c, altNamespace) util_err.Err_log(err) err = agnosticIncrement(c) util_err.Err_log(err) } s := `counters updates für ns='' and ns='ns01'.` + "\n" io.WriteString(w, s) readBothNamespaces(w, r) }
// See https://developers.google.com/appengine/docs/go/datastore/entities#Go_Kinds_and_identifiers func CreateKey(c appengine.Context, appID string, namespace string, kind string, stringID string, intID int64, parent *datastore.Key) (*datastore.Key, error) { // c is the true context of the current request // forged is a wrapper context with our custom appID forged := &ForgedContext{c, appID} // cc is a wrapper context with our custom namespace cc, err := appengine.Namespace(forged, namespace) if err != nil { return nil, err } key := datastore.NewKey( cc, // appengine.Context. kind, // Kind. stringID, // String ID; empty means no string ID. intID, // Integer ID; if 0, generate automatically. Ignored if string ID specified. parent, // Parent Key; nil means no parent. ) return key, nil }
func incrementBothNamespaces(w http.ResponseWriter, r *http.Request, m map[string]interface{}) { lg, b := loghttp.BuffLoggerUniversal(w, r) _ = b c := appengine.NewContext(r) err := agnosticIncrement(c) lg(err) { c, err := appengine.Namespace(c, altNamespace) lg(err) err = agnosticIncrement(c) lg(err) } s := `counters updates für ns='' and ns='ns01'.` + "\n" io.WriteString(w, s) readBothNamespaces(w, r, m) }
// Create begins creating a new blob. The provided mimeType if non-empty // is stored in the blob's BlobInfo in datastore, else defaults to // application/octet-stream. The returned Writer should be written to, // then closed, and then its Key method can be called to retrieve the // newly-created blob key if there were no errors. func Create(c appengine.Context, mimeType string) (*Writer, error) { c, _ = appengine.Namespace(c, "") // Blobstore is always in the empty string namespace if mimeType == "" { mimeType = "application/octet-stream" } req := &filepb.CreateRequest{ Filesystem: proto.String("blobstore"), ContentType: filepb.FileContentType_RAW.Enum(), Parameters: []*filepb.CreateRequest_Parameter{ { Name: proto.String("content_type"), Value: proto.String(mimeType), }, }, } res := &filepb.CreateResponse{} if err := c.Call("file", "Create", req, res, nil); err != nil { return nil, err } w := &Writer{ c: c, filename: *res.Filename, } if !strings.HasPrefix(w.filename, blobstoreFileDirectory) { return nil, errorf("unexpected filename from files service: %q", w.filename) } oreq := &filepb.OpenRequest{ Filename: res.Filename, ContentType: filepb.FileContentType_RAW.Enum(), OpenMode: filepb.OpenRequest_APPEND.Enum(), ExclusiveLock: proto.Bool(true), } ores := &filepb.OpenResponse{} if err := c.Call("file", "Open", oreq, ores, nil); err != nil { return nil, err } return w, nil }
func queuePush(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) m := map[string][]string{"counter_name": []string{nscStringKey}} t := taskqueue.NewPOSTTask("/_ah/namespaced-counters/queue-pop", m) taskqueue.Add(c, t, "") c, err := appengine.Namespace(c, altNamespace) util_err.Err_log(err) taskqueue.Add(c, t, "") io.WriteString(w, "tasks enqueued\n") io.WriteString(w, "\ncounter values now: \n") readBothNamespaces(w, r) io.WriteString(w, "\n\n...sleeping... \n") time.Sleep(time.Duration(400) * time.Millisecond) readBothNamespaces(w, r) }
func context(r *http.Request) appengine.Context { c := appengine.NewContext(r) nc, _ := appengine.Namespace(c, Namespace) return nc }
func TestGetCachedCertsCacheMiss(t *testing.T) { rt := newTestRoundTripper() origTransport := httpTransportFactory defer func() { httpTransportFactory = origTransport }() httpTransportFactory = func(c appengine.Context) http.RoundTripper { return rt } req, _, closer := newTestRequest(t, "GET", "/", nil) defer closer() nc, err := appengine.Namespace(appengine.NewContext(req), certNamespace) if err != nil { t.Fatal(err) } ec := NewContext(req) tts := []*struct { respStatus int respContent, cacheControl, age string want *certsList shouldCache bool }{ {200, `{"keyvalues":null}`, "max-age=3600", "600", &certsList{}, true}, {-1, "", "", "", nil, false}, {400, "", "", "", nil, false}, {200, `{"keyvalues":null}`, "", "", &certsList{}, false}, } for i, tt := range tts { if tt.respStatus > 0 { resp := &http.Response{ Status: fmt.Sprintf("%d", tt.respStatus), StatusCode: tt.respStatus, Body: ioutil.NopCloser(strings.NewReader(tt.respContent)), Header: make(http.Header), } resp.Header.Set("cache-control", tt.cacheControl) resp.Header.Set("age", tt.age) rt.Add(resp) } memcache.Delete(nc, DefaultCertURI) out, err := getCachedCerts(ec) switch { case err != nil && tt.want != nil: t.Errorf("%d: getCachedCerts() = %v", i, err) case err == nil && tt.want == nil: t.Errorf("%d: getCachedCerts() = %#v; want error", i, out) default: if !reflect.DeepEqual(out, tt.want) { t.Errorf("%d: getCachedCerts() = %#v; want %#v", i, out, tt.want) } if !tt.shouldCache { continue } item, err := memcache.Get(nc, DefaultCertURI) if err != nil { t.Errorf("%d: memcache.Get(%q) = %v", i, DefaultCertURI, err) continue } cert := string(item.Value) if tt.respContent != cert { t.Errorf("%d: memcache.Get(%q) = %q; want %q", i, DefaultCertURI, cert, tt.respContent) } } } }
func TestCurrentUser(t *testing.T) { const ( // Default values from user_service_stub.py of dev_appserver2. clientID = "123456789.apps.googleusercontent.com" bearerEmail = "*****@*****.**" validScope = "valid.scope" ) inst, err := aetest.NewInstance(nil) if err != nil { t.Fatalf("failed to create instance: %v", err) } defer inst.Close() req, err := inst.NewRequest("GET", "/", nil) nc, err := appengine.Namespace(appengine.NewContext(req), certNamespace) if err != nil { t.Fatal(err) } // googCerts are provided in jwt_test.go item := &memcache.Item{Key: DefaultCertURI, Value: []byte(googCerts)} if err := memcache.Set(nc, item); err != nil { t.Fatal(err) } origCurrentUTC := currentUTC defer func() { currentUTC = origCurrentUTC }() currentUTC = func() time.Time { return jwtValidTokenTime } jwtStr, jwt := jwtValidTokenString, jwtValidTokenObject tts := []struct { token string scopes, audiences, clientIDs []string wantEmail string }{ // success {jwtStr, []string{EmailScope}, []string{jwt.Audience}, []string{jwt.ClientID}, jwt.Email}, {"ya29.token", []string{EmailScope}, []string{clientID}, []string{clientID}, bearerEmail}, {"ya29.token", []string{EmailScope, validScope}, []string{clientID}, []string{clientID}, bearerEmail}, {"1/token", []string{validScope}, []string{clientID}, []string{clientID}, bearerEmail}, // failure {jwtStr, []string{EmailScope}, []string{"other-client"}, []string{"other-client"}, ""}, {"some.invalid.jwt", []string{EmailScope}, []string{jwt.Audience}, []string{jwt.ClientID}, ""}, {"", []string{validScope}, []string{clientID}, []string{clientID}, ""}, // The following test is commented for now because default implementation // of UserServiceStub in dev_appserver2 allows any scope. // TODO: figure out how to test this. //{"ya29.invalid", []string{"invalid.scope"}, []string{clientID}, []string{clientID}, ""}, {"doesn't matter", nil, []string{clientID}, []string{clientID}, ""}, {"doesn't matter", []string{EmailScope}, nil, []string{clientID}, ""}, {"doesn't matter", []string{EmailScope}, []string{clientID}, nil, ""}, } for i, tt := range tts { r, err := inst.NewRequest("GET", "/", nil) c := cachingContextFactory(r) if tt.token != "" { r.Header.Set("authorization", "oauth "+tt.token) } user, err := CurrentUser(c, tt.scopes, tt.audiences, tt.clientIDs) switch { case tt.wantEmail == "" && err == nil: t.Errorf("%d: CurrentUser(%v, %v, %v) = %v; want error", i, tt.scopes, tt.audiences, tt.clientIDs, user) case tt.wantEmail != "" && user == nil: t.Errorf("%d: CurrentUser(%v, %v, %v) = %v; want email = %q", i, tt.scopes, tt.audiences, tt.clientIDs, err, tt.wantEmail) case tt.wantEmail != "" && tt.wantEmail != user.Email: t.Errorf("%d: CurrentUser(%v, %v, %v) = %v; want email = %q", i, tt.scopes, tt.audiences, tt.clientIDs, user, tt.wantEmail) } } }
func loadJsonToDatastore(ctx appengine.Context, pkey *datastore.Key, data map[string]interface{}, logger wcg.Logger) error { var kind string var ns string var keyval interface{} var key *datastore.Key var ok bool var err error if _, ok = data["_kind"]; !ok { return fmt.Errorf("Missing key `_kind`") } else { kind = data["_kind"].(string) } if keyval, ok = data["_key"]; !ok { return fmt.Errorf("Missing key `_key`") } if _, ok = data["_ns"]; ok { ns = data["_ns"].(string) ctx, err = appengine.Namespace(ctx, ns) if err != nil { return err } } switch keyval.(type) { case int64: key = datastore.NewKey(ctx, kind, "", keyval.(int64), pkey) case string: key = datastore.NewKey(ctx, kind, keyval.(string), 0, pkey) default: return fmt.Errorf("Invalid `_key` type.") } if _, err := datastore.Put(ctx, key, JsonSaver(data)); err != nil { return err } // Check the data is actually stored. if err := wcg.RetryUntil(func() error { var v JsonSaver if err := datastore.Get(ctx, key, &v); err != nil { return fmt.Errorf( "fixture is not synched on '%s:[%s]': internal error?(%v) on ", kind, keyval, err, ) } return nil }, 5*time.Second, 500*time.Millisecond); err != nil { return err } logger.Debug("[Fixture] %s%s -- %v", ns, key, data) for _, v := range data { // Child object if child, ok := v.(map[string]interface{}); ok { if err := loadJsonToDatastore(ctx, key, child, logger); err != nil { return err } continue } // Array if children, ok := v.([]interface{}); ok { for _, child := range children { if c, ok := child.(map[string]interface{}); ok { if err := loadJsonToDatastore(ctx, key, c, logger); err != nil { return err } } } continue } } return nil }
func (c Context) storeContext() appengine.Context { nc, _ := appengine.Namespace(c.Context, Namespace) return nc }