func TestStackErrorString(t *testing.T) { t.Parallel() h := newHarness(t) defer h.Stop() err := stackerr.New("error") h.env.ErrorStack = false errStr := errorString(h.env, err) ensure.DeepEqual(t, errStr, "error") h.env.ErrorStack = true errStr = errorString(h.env, err) ensure.StringContains(t, errStr, "error") ensure.StringContains(t, errStr, ".go") err = stackerr.Wrap(&parse.Error{Message: "message", Code: 1}) h.env.ErrorStack = false errStr = errorString(h.env, err) ensure.DeepEqual(t, errStr, "message") h.env.ErrorStack = true errStr = errorString(h.env, err) ensure.StringContains(t, errStr, `parse: api error with code=1 and message="message`) ensure.StringContains(t, errStr, ".go") }
func TestMultiErrorString(t *testing.T) { t.Parallel() h := newHarness(t) defer h.Stop() err := errgroup.MultiError( []error{ stackerr.New("error"), stackerr.Wrap(&parse.Error{Message: "message", Code: 1}), }, ) h.env.ErrorStack = false errStr := errorString(h.env, err) ensure.DeepEqual(t, errStr, "multiple errors: error | message") h.env.ErrorStack = true errStr = errorString(h.env, err) ensure.StringContains(t, errStr, "multiple errors") ensure.StringContains(t, errStr, `parse: api error with code=1 and message="message"`) ensure.StringContains(t, errStr, ".go") }
func TestProjectType(t *testing.T) { t.Parallel() h := parsecli.NewHarness(t) defer h.Stop() h.MakeEmptyRoot() ensure.Nil(t, parsecli.CloneSampleCloudCode(h.Env, false)) c := &configureCmd{} err := c.projectType(h.Env, []string{"1", "2"}) ensure.Err(t, err, regexp.MustCompile("only an optional project type argument is expected")) h.Env.In = ioutil.NopCloser(strings.NewReader("invalid\n")) err = c.projectType(h.Env, nil) ensure.StringContains(t, h.Err.String(), "Invalid selection. Please enter a number") ensure.Err(t, err, regexp.MustCompile("Could not make a selection. Please try again.")) h.Err.Reset() h.Out.Reset() h.Env.In = ioutil.NopCloser(strings.NewReader("0\n")) err = c.projectType(h.Env, nil) ensure.StringContains(t, h.Err.String(), "Please enter a number between 1 and") ensure.Err(t, err, regexp.MustCompile("Could not make a selection. Please try again.")) h.Err.Reset() h.Out.Reset() h.Env.In = ioutil.NopCloser(strings.NewReader("1\n")) err = c.projectType(h.Env, nil) ensure.StringContains(t, h.Out.String(), "Successfully set project type to: parse") ensure.Nil(t, err) }
func TestEnvCmd(t *testing.T) { t.Parallel() stdout, stderr := testRunCmd(t, "hostctl env", 0, nil, nil) ensure.StringContains(t, stdout.String(), "HOSTCTL_PROVIDER=") ensure.StringContains(t, stdout.String(), "HOSTCTL_NAMESPACE=") ensure.DeepEqual(t, stderr.String(), "") }
func TestHostctlCmd(t *testing.T) { t.Parallel() stdout, stderr := testRunCmd(t, "hostctl", 0, nil, nil) ensure.StringContains(t, stdout.String(), Hostctl.Short) ensure.StringContains(t, stdout.String(), "Usage:") ensure.StringContains(t, stdout.String(), "Available Commands:") ensure.StringContains(t, stdout.String(), "Flags:") ensure.DeepEqual(t, stderr.String(), "") }
func TestPageTabURL(t *testing.T) { t.Parallel() env, _ := fromValues(t, url.Values{}) pageTabURL := env.PageTabURL("/") ensure.StringContains(t, pageTabURL, "http://www.facebook.com/pages/Rell-Page-for-Tabs/141929622497380") ensure.StringContains(t, pageTabURL, fmt.Sprintf("app_%d", defaultFacebookAppID)) ensure.StringContains(t, pageTabURL, "app_data=Lw%3D%3D") }
func TestErrorStringWithStack(t *testing.T) { t.Parallel() h := newHarness(t) defer h.Stop() h.env.ErrorStack = true const message = "hello world" actual := errorString(h.env, stackerr.New(message)) ensure.StringContains(t, actual, message) ensure.StringContains(t, actual, ".go") }
func TestCanvasURL(t *testing.T) { t.Parallel() env, _ := fromValues(t, url.Values{}) canvasURL := env.CanvasURL("/") ensure.StringContains(t, canvasURL, fmt.Sprintf("https://apps.facebook.com/%s/", defaultAppNS)) }
func TestCanvasURLBeta(t *testing.T) { t.Parallel() env, _ := fromValues(t, url.Values{"server": []string{"beta"}}) canvasURL := env.CanvasURL("/") ensure.StringContains(t, canvasURL, fmt.Sprintf("https://apps.beta.facebook.com/%s/?server=beta", defaultAppNS)) }
func TestPageTabURLBeta(t *testing.T) { t.Parallel() env, _ := fromValues(t, url.Values{"server": []string{"beta"}}) pageTabURL := env.PageTabURL("/") ensure.StringContains(t, pageTabURL, "http://www.beta.facebook.com/pages/Rell-Page-for-Tabs/141929622497380") }
func TestLatestVersion(t *testing.T) { t.Parallel() h := parsecli.NewHarness(t) defer h.Stop() ht := parsecli.TransportFunc(func(r *http.Request) (*http.Response, error) { ensure.DeepEqual(t, r.URL.Path, "/1/supported") return &http.Response{ StatusCode: http.StatusOK, Body: ioutil.NopCloser( jsonpipe.Encode( map[string]string{"version": "2.0.2"}, ), ), }, nil }) h.Env.ParseAPIClient = &parsecli.ParseAPIClient{APIClient: &parse.Client{Transport: ht}} u := new(updateCmd) latestVersion, err := u.latestVersion(h.Env) ensure.Nil(t, err) ensure.DeepEqual(t, latestVersion, "2.0.2") downloadURL, err := u.getDownloadURL(h.Env) ensure.StringContains(t, downloadURL, "https://github.com/ParsePlatform/parse-cli/releases/download/release_2.0.2") }
func TestErrorStringWithoutStack(t *testing.T) { t.Parallel() h := NewHarness(t) defer h.Stop() h.Env.ErrorStack = false const message = "hello world" actual := ErrorString(h.Env, stackerr.New(message)) ensure.StringContains(t, actual, message) ensure.StringDoesNotContain(t, actual, ".go") }
func TestMultiLineStringContains(t *testing.T) { var c capture ensure.StringContains(&c, "foo\nbaz", "bar") c.Equal(t, `ensure_test.go:245: expected substring was not found: EXPECTED SUBSTRING: bar ACTUAL: foo baz`) }
func TestSelectNewAppNoCode(t *testing.T) { t.Parallel() h, _ := parsecli.NewAppHarness(t) defer h.Stop() h.Env.In = ioutil.NopCloser(strings.NewReader("email\npassword\n")) n := &newCmd{noCode: true, parseAppName: "A"} ensure.Nil(t, n.run(h.Env)) ensure.StringContains(t, h.Out.String(), "Successfully selected") }
func TestGetCloudCodeDir(t *testing.T) { t.Parallel() h := parsecli.NewHarness(t) h.MakeEmptyRoot() defer h.Stop() n := &newCmd{} h.Env.In = ioutil.NopCloser(strings.NewReader("\n")) name, err := n.getCloudCodeDir(h.Env, "myapp", true) ensure.Nil(t, err) ensure.StringContains(t, h.Out.String(), "Now it's time to set up some Cloud Code") ensure.DeepEqual(t, name, "myapp") h.Out.Reset() h.Env.In = ioutil.NopCloser(strings.NewReader("otherApp\n")) name, err = n.getCloudCodeDir(h.Env, "myapp", true) ensure.Nil(t, err) ensure.StringContains(t, h.Out.String(), "Now it's time to set up some Cloud Code") ensure.DeepEqual(t, name, "otherApp") _, err = os.Create(filepath.Join(h.Env.Root, "otherApp")) ensure.Nil(t, err) h.Out.Reset() h.Env.In = ioutil.NopCloser(strings.NewReader("otherApp\n")) name, err = n.getCloudCodeDir(h.Env, "myapp", true) ensure.Err(t, err, regexp.MustCompile("already exists")) ensure.StringContains(t, h.Out.String(), "Now it's time to set up some Cloud Code") ensure.Nil(t, os.MkdirAll(filepath.Join(h.Env.Root, "myapp", "config"), 0755)) _, err = os.Create(filepath.Join(h.Env.Root, "myapp", "config", "global.json")) ensure.Nil(t, err) h.Out.Reset() h.Env.In = ioutil.NopCloser(strings.NewReader("\n")) name, err = n.getCloudCodeDir(h.Env, "myapp", true) ensure.Err(t, err, regexp.MustCompile("you already have Cloud Code")) ensure.Nil(t, os.Remove(filepath.Join(h.Env.Root, "myapp", "config", "global.json"))) h.Out.Reset() h.Env.In = ioutil.NopCloser(strings.NewReader("\n")) name, err = n.getCloudCodeDir(h.Env, "myapp", false) ensure.Nil(t, err) ensure.StringContains(t, h.Out.String(), "folder where we can download the latest") }
func TestRunListCmd(t *testing.T) { t.Parallel() h, _ := newAppHarness(t) defer h.Stop() l := &listCmd{} h.env.In = ioutil.NopCloser(strings.NewReader("email\npassword\n")) ensure.Nil(t, l.run(h.env, []string{"A"})) ensure.StringContains(t, h.Out.String(), `Properties of the app "A"`) }
func TestRunNoArgsWithArg(t *testing.T) { t.Parallel() h := newHarness(t) defer h.Stop() h.env.Exit = func(i int) { panic(exitCode(i)) } func() { defer ensure.PanicDeepEqual(t, exitCode(1)) r := runNoArgs(h.env, nil) r(noOpCmd(), []string{"foo"}) }() ensure.StringContains(t, h.Err.String(), "unexpected arguments") }
func TestCreateNewAppNameTaken(t *testing.T) { t.Parallel() h, _ := NewAppHarness(t) defer h.Stop() a := defaultApps h.Env.In = ioutil.NopCloser(strings.NewReader("A\nD")) _, err := a.CreateApp(h.Env, "", 0) ensure.Nil(t, err) ensure.StringContains(t, h.Err.String(), "already created an app") }
func TestRunNoArgsFuncError(t *testing.T) { t.Parallel() const message = "hello world" h := newHarness(t) defer h.Stop() h.env.Exit = func(i int) { panic(exitCode(i)) } func() { defer ensure.PanicDeepEqual(t, exitCode(1)) r := runNoArgs(h.env, func(*env) error { return errors.New(message) }) r(noOpCmd(), nil) }() ensure.StringContains(t, h.Err.String(), message) }
func TestRunWithAppNotFound(t *testing.T) { t.Parallel() h := newHarness(t) defer h.Stop() c := legacyConfig{Applications: map[string]*parseAppConfig{"a": {}}} h.makeWithConfig(jsonStr(t, c)) h.env.Exit = func(i int) { panic(exitCode(i)) } func() { defer ensure.PanicDeepEqual(t, exitCode(1)) r := runWithClient(h.env, nil) r(noOpCmd(), []string{"b"}) }() ensure.StringContains(t, h.Err.String(), `App "b" wasn't found`) }
func TestComplex(t *testing.T) { t.Parallel() values := url.Values{} values.Add("status", "1") values.Add("server", "beta") values.Add("locale", "en_PI") expected := &rellenv.Env{ Status: true, Env: "beta", } env, _ := fromValues(t, values) ensure.Subset(t, env, expected) ensure.StringContains(t, env.SdkURL(), "en_PI") }
func TestRunWithAppMultipleArgs(t *testing.T) { t.Parallel() h := newHarness(t) defer h.Stop() h.env.Exit = func(i int) { panic(exitCode(i)) } func() { defer ensure.PanicDeepEqual(t, exitCode(1)) r := runWithClient(h.env, nil) r(noOpCmd(), []string{"foo", "bar"}) }() ensure.StringContains( t, h.Err.String(), "only an optional app name is expected", ) }
func TestRunMigrateCmd(t *testing.T) { t.Parallel() h := parsecli.NewHarness(t) h.MakeEmptyRoot() defer h.Stop() n := &newCmd{} h.Env.Type = parsecli.ParseFormat h.Env.In = ioutil.NopCloser(strings.NewReader("\n")) _, err := n.setupSample(h.Env, "yolo", &parsecli.ParseAppConfig{ ApplicationID: "yolo-id", MasterKey: "yoda", }, false, false, ) ensure.Nil(t, err) m := &migrateCmd{} err = m.run(h.Env) ensure.Err(t, err, regexp.MustCompile("Already using the preferred config format")) ensure.Nil(t, os.Remove(filepath.Join(h.Env.Root, parsecli.ParseLocal))) ensure.Nil(t, os.Remove(filepath.Join(h.Env.Root, parsecli.ParseProject))) ensure.Nil(t, os.MkdirAll(filepath.Join(h.Env.Root, parsecli.ConfigDir), 0755)) ensure.Nil(t, ioutil.WriteFile( filepath.Join(h.Env.Root, parsecli.LegacyConfigFile), []byte(`{ "applications": { "yolo": { "applicationId": "yolo-id", "masterKey": "yoda" } } }`), 0600, ), ) ensure.Nil(t, m.run(h.Env)) ensure.StringContains(t, h.Out.String(), "Successfully migrated") }
func TestRunWithAppNonProjectDir(t *testing.T) { t.Parallel() h := newHarness(t) defer h.Stop() h.makeEmptyRoot() h.env.Exit = func(i int) { panic(exitCode(i)) } func() { defer ensure.PanicDeepEqual(t, exitCode(1)) r := runWithClient(h.env, nil) r(noOpCmd(), nil) }() ensure.StringContains( t, h.Err.String(), "Command must be run inside a Parse project.", ) }
func TestCloudCodeHelpMessage(t *testing.T) { t.Parallel() h := parsecli.NewHarness(t) defer h.Stop() n := &newCmd{} msg := n.cloudCodeHelpMessage(h.Env, &parsecli.App{ApplicationID: "a", MasterKey: "m"}) ensure.StringContains(t, msg, fmt.Sprintf( `Your Cloud Code has been created at %s. This includes a "Hello world" cloud function, so once you deploy, you can test that it works, with`, h.Env.Root, ), ) }
func TestContDeployConfigErr(t *testing.T) { t.Parallel() h := createParseProject(t) defer h.Stop() ensure.Nil(t, ioutil.WriteFile( filepath.Join(h.env.Root, legacyConfigFile), []byte("}"), 0600, ), ) h.env.Type = legacy deployer := deployFunc(func(parseVersion string, prevDeplInfo *deployInfo, forDevelop bool, e *env) (*deployInfo, error) { return &deployInfo{}, nil }) done := make(chan struct{}) go func() { h.Clock.Add(5 * time.Second) close(done) }() first := make(chan struct{}) (&developCmd{}).contDeploy(h.env, deployer, first, done) _, opened := <-first ensure.False(t, opened) ensure.StringContains( t, h.Err.String(), fmt.Sprintf( `Config malformed. Please fix your config file in %s and try again. `, filepath.Join(h.env.Root, legacyConfigFile), ), ) }
func TestRunWithAppError(t *testing.T) { t.Parallel() h := newHarness(t) defer h.Stop() const appName = "a" c := &parseConfig{ Applications: map[string]*parseAppConfig{ appName: {ApplicationID: "id", MasterKey: "token"}, }, } h.makeWithConfig(jsonStr(t, c)) h.env.Exit = func(i int) { panic(exitCode(i)) } const message = "hello world" func() { defer ensure.PanicDeepEqual(t, exitCode(1)) r := runWithClient(h.env, func(e *env, c *context) error { ensure.NotNil(t, c) return errors.New(message) }) r(noOpCmd(), []string{"a"}) }() ensure.StringContains(t, h.Err.String(), message) }
func TestConfigureAccountKey(t *testing.T) { t.Parallel() h := parsecli.NewTokenHarness(t) defer h.Stop() c := configureCmd{login: parsecli.Login{TokenReader: strings.NewReader("")}} h.Env.In = ioutil.NopCloser(strings.NewReader("token\n")) ensure.Nil(t, c.accountKey(h.Env)) ensure.StringContains( t, h.Out.String(), ` Input your account key or press ENTER to generate a new one. `) h.Env.In = ioutil.NopCloser(strings.NewReader("invalid\n")) ensure.Err(t, c.accountKey(h.Env), regexp.MustCompile("is not valid")) ensure.DeepEqual(t, h.Err.String(), "Could not store credentials. Please try again.\n\n", ) h.Env.Server = "http://api.parse.com/1/" c.tokenReader = strings.NewReader( `machine api.parse.com#email login default password token2 `, ) h.Err.Reset() h.Env.In = ioutil.NopCloser(strings.NewReader("token\n")) ensure.Nil(t, c.accountKey(h.Env)) ensure.DeepEqual(t, h.Err.String(), `Note: this operation will overwrite the account key: "*oken" for email: "email" `) h.Env.Server = "http://api.parse.com/1/" c.tokenReader = strings.NewReader( `machine api.parse.com#email login default password token2 `, ) c.isDefault = true h.Err.Reset() h.Env.In = ioutil.NopCloser(strings.NewReader("token\n")) ensure.Nil(t, c.accountKey(h.Env)) ensure.DeepEqual(t, h.Err.String(), "") h.Env.Server = "http://api.parse.com/1/" c.tokenReader = strings.NewReader( `machine api.parse.com login default password token2 `, ) c.isDefault = true h.Err.Reset() h.Env.In = ioutil.NopCloser(strings.NewReader("token\n")) ensure.Nil(t, c.accountKey(h.Env)) ensure.DeepEqual(t, h.Err.String(), "Note: this operation will overwrite the default account key\n") h.Env.Server = "http://api.parse.com/1/" c.tokenReader = strings.NewReader( `machine api.parse.com login default password token2 `, ) h.Err.Reset() c.isDefault = false h.Env.In = ioutil.NopCloser(strings.NewReader("token\n")) ensure.Nil(t, c.accountKey(h.Env)) ensure.DeepEqual(t, h.Err.String(), "") }
func TestGetRandomAppName(t *testing.T) { app := &parsecli.App{Name: "test app", ApplicationID: "123456789"} name := getRandomAppName(app) ensure.StringContains(t, name, "testapp") }
func TestErrorCases(t *testing.T) { cases := []struct { Request *http.Request Body interface{} Error string StatusCode int Transport http.RoundTripper }{ { Request: &http.Request{ Method: "GET", URL: &url.URL{ Scheme: "https", Host: "api.parse.com", Path: "/1/classes/Foo/Bar", }, }, Error: `parse: api error with code=101 and message="object not found for get"`, StatusCode: http.StatusNotFound, Transport: transportFunc(func(r *http.Request) (*http.Response, error) { j := jsonB(t, parse.Error{ Code: 101, Message: "object not found for get", }) return &http.Response{ StatusCode: http.StatusNotFound, Status: "404 Not Found", Body: ioutil.NopCloser(bytes.NewReader(j)), }, nil }), }, { Request: &http.Request{ Method: "GET", URL: &url.URL{ Scheme: "https", Host: "api.parse.com", Path: "/1/classes/Foo/Bar", }, }, Body: map[int]int{}, Error: "unsupported type: map[int]int", Transport: transportFunc(func(r *http.Request) (*http.Response, error) { panic("not reached") }), }, { Request: &http.Request{ Method: "GET", URL: &url.URL{Path: "/"}, }, Error: `error with status=404 and body="<html>`, StatusCode: 404, Transport: transportFunc(func(r *http.Request) (*http.Response, error) { return &http.Response{ StatusCode: http.StatusNotFound, Status: "404 Not Found", Body: ioutil.NopCloser(strings.NewReader("<html>")), }, nil }), }, } t.Parallel() for _, ec := range cases { c := &parse.Client{ Credentials: defaultRestAPIKey, } if !realTransport { c.Transport = ec.Transport } res, err := c.Do(ec.Request, ec.Body, nil) ensure.NotNil(t, err) ensure.StringContains(t, err.Error(), ec.Error, ec) if ec.StatusCode != 0 { ensure.False(t, res == nil, ec) ensure.DeepEqual(t, res.StatusCode, ec.StatusCode, ec) } } }