Example #1
0
// CleanupDatastore is to remove all data in datastore
func CleanupDatastore(ctx context.Context, namespaces ...string) error {
	var dummy []interface{}
	logger := wcg.NewLogger(nil)
	logger.Debugf("[Fixture] --------- CleanupDatastore ---------")
	namespaceList := append(namespaces, "")
	for _, ns := range namespaceList {
		logger.Debugf("[Fixture] Cleanup: ns=%q", ns)
		var _ctx = ctx
		if ns != "" {
			_ctx, _ = appengine.Namespace(_ctx, ns)
		}
		err := wcg.RetryUntil(func() error {
			var keys []*datastore.Key
			var err error
			if keys, err = datastore.NewQuery("").KeysOnly().GetAll(_ctx, dummy); err != nil {
				return err
			}
			if err := datastore.DeleteMulti(_ctx, keys); err != nil {
				return err
			}
			count, _ := datastore.NewQuery("").KeysOnly().Count(_ctx)
			if count == 0 {
				return nil
			}
			return fmt.Errorf("Still have %d keys.", count)
		}, 10*time.Second, 100*time.Millisecond)
		if err != nil {
			return err
		}
	}
	return nil
}
Example #2
0
func loadJsonToDatastore(ctx context.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`")
	}
	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 fmt.Errorf("Could not change the namespace of %q, check _ns value: ", ns, 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.Debugf("[Fixture] %s%s -- %v", ns, key, data)
	if children, ok := data["_children"]; ok {
		for _, v := range children.([]interface{}) {
			if err := loadJsonToDatastore(ctx, key, v.(map[string]interface{}), logger); err != nil {
				return err
			}
		}
	}
	return nil
}
Example #3
0
// NewTestServer creates a new *TestServer
func NewTestServer() *TestServer {
	checkLimits()
	instance, err := aetest.NewInstance(&aetest.Options{
		AppID: "wcgapptest",
		StronglyConsistentDatastore: true,
	})
	if err != nil {
		panic(fmt.Errorf("aetest.NewInstance returns an error: %v", err))
	}
	req, err := instance.NewRequest("GET", "/", nil)
	if err != nil {
		instance.Close()
		panic(fmt.Errorf("cannot create a new request for aetest.Instance: %v", err))
	}
	var ctx context.Context
	err = wcg.RetryUntil(func() error {
		var err error
		defer func() {
			if x := recover(); x != nil {
				err = fmt.Errorf("Unknown error: %v", x)
			}
		}()
		ctx = appengine.NewContext(req)
		return err
	}, 5*time.Second, 200*time.Millisecond)

	// reset sinks
	level, err := wcg.ParseLogLevel(os.Getenv("LOGGING_LEVEL"))
	if err == nil {
		wcg.DefaultLogConfig.Level = level
	}
	wcg.DefaultLogConfig.ConfigureSinks()
	wcg.DefaultLogConfig.AddSink(
		gae.NewLogSinkWithContext(gae.LogSinkConfig.Format, ctx),
		level,
	)
	ts := &TestServer{
		Context:  ctx,
		instance: instance,
	}
	return ts
}
Example #4
0
// Run to run an async task by calling an AsyncAPI endpoint.
func (runner *AsyncTaskTestRunner) Run(path string, query url.Values) *models.AsyncAPITask {
	type TriggerResponse struct {
		ID wcg.UUID `json:"id"`
	}
	type MonitorResponse struct {
		ID     wcg.UUID              `json:"id"`
		Status models.AsyncAPIStatus `json:"status"`
	}
	var t = runner.t
	var ts = runner.ts
	var router = runner.router
	var triggered TriggerResponse
	var monitor MonitorResponse

	var onTrigger = runner.onTrigger
	var onMonitor = runner.onMonitor
	if onTrigger == nil {
		onTrigger = func(_ *httptest.TestRequest, f func()) { f() }
	}
	if onMonitor == nil {
		onMonitor = func(_ *httptest.TestRequest, f func()) { f() }
	}

	// Request to the trigger endpoint
	assert := gaetest.NewAssert(t)
	triggerPath := path
	if query != nil {
		triggerPath = fmt.Sprintf("%s?%s", triggerPath, query.Encode())
	}
	req := ts.POSTForm(triggerPath, nil)
	onTrigger(req, func() {
		res := req.RouteTo(router)
		assert.HTTPStatus(201, res)
		assert.JSONResponse(&triggered, res)
	})

	// Reqeust to the execution endpoint since no module is loaded on test server.
	go func() {
		basePath := fmt.Sprintf("%s%s.json", path, triggered.ID)
		execPath := basePath
		if query != nil {
			execPath = fmt.Sprintf("%s?%s", basePath, query.Encode())
		}
		for execPath != "" {
			req := ts.POSTForm(execPath, nil)
			req.AddHeader("X-AppEngine-TaskName", "runasynctasktest")
			res := req.RouteTo(router)
			if res.Code == 200 {
				var next url.Values
				if err := json.Unmarshal(res.Body, &next); err == nil {
					execPath = fmt.Sprintf("%s?%s", basePath, next.Encode())
				} else {
					execPath = ""
				}
			} else {
				execPath = ""
			}
		}
	}()

	err := wcg.RetryUntil(func() error {
		req := ts.GET(fmt.Sprintf("%s%s.json", path, triggered.ID))
		onMonitor(req, func() {
			res := req.RouteTo(router)
			assert.HTTPStatus(200, res)
			assert.JSONResponse(&monitor, res)
		})
		if monitor.Status == models.AsyncAPIStatusSuccess ||
			monitor.Status == models.AsyncAPIStatusFailure {
			return nil
		}
		return fmt.Errorf("Task is running")
	}, _runAsyncTaskTestTimeout, _runAsyncTaskTestInterval)
	if err != nil {
		assert.Fatalf("AsyncTask timed out")
		return nil
	}
	_, one := entities.AsyncAPITask.Get().Key(string(triggered.ID)).MustOne(ts.GET("/").Request)
	assert.NotNil(one)
	return one.(*models.AsyncAPITask)
}