Ejemplo n.º 1
0
func TestMultiServiceGeneratorGenerate(t *testing.T) {
	type response struct {
		success *api.GenerateServiceResponse
		failure error
	}

	tests := []struct {
		desc string

		// list of responses from different service generators
		responses []response

		// final expected response or errors
		wantResponse    *api.GenerateServiceResponse
		wantErrors      []string
		wantOneOfErrors []string
		// both, wantErrors and wantOneOfErrors may be set. All errors in
		// wantErrors must be present, but only one or more of the errors in
		// wantOneOfErrors must be present.
	}{
		{
			desc: "no conflicts; no errors",
			responses: []response{
				{success: &api.GenerateServiceResponse{Files: map[string][]byte{
					"foo/a.go": {1, 2, 3},
					"foo/b.go": {4, 5, 6},
				}}},
				{success: &api.GenerateServiceResponse{Files: map[string][]byte{
					"foo/c.go": {7, 8, 9},
					"foo/d.go": {1, 2, 3},
				}}},
				{success: &api.GenerateServiceResponse{Files: map[string][]byte{
				// no files
				}}},
				{success: &api.GenerateServiceResponse{Files: map[string][]byte{
					"foo/keyvalue/e.go": {4, 5, 6},
				}}},
			},
			wantResponse: &api.GenerateServiceResponse{Files: map[string][]byte{
				"foo/a.go":          {1, 2, 3},
				"foo/b.go":          {4, 5, 6},
				"foo/c.go":          {7, 8, 9},
				"foo/d.go":          {1, 2, 3},
				"foo/keyvalue/e.go": {4, 5, 6},
			}},
		},
		{
			desc: "no conflicts; with errors",
			responses: []response{
				{failure: errors.New("foo: great sadness")},
				{success: &api.GenerateServiceResponse{Files: map[string][]byte{
					"foo/a.go": {1, 2, 3},
				}}},
				{success: &api.GenerateServiceResponse{Files: map[string][]byte{
					"foo/b.go": {4, 5, 6},
				}}},
				{failure: errors.New("bar: great sadness")},
			},
			wantErrors: []string{
				`foo: great sadness`,
				`bar: great sadness`,
			},
		},
		{
			desc: "conflicts",
			responses: []response{
				{success: &api.GenerateServiceResponse{Files: map[string][]byte{
					"foo/a.go": {1, 2, 3},
					"foo/b.go": {4, 5, 6},
				}}},
				{success: &api.GenerateServiceResponse{Files: map[string][]byte{
					"foo/c.go": {7, 8, 9},
					"foo/b.go": {1, 2, 3},
				}}},
			},
			wantErrors: []string{`plugin conflict: cannot write file "foo/b.go" for plugin`},
			wantOneOfErrors: []string{
				`plugin "plugin-1" already wrote to that file`,
				`plugin "plugin-0" already wrote to that file`,
			},
		},
	}

	req := &api.GenerateServiceRequest{
		RootServices: []api.ServiceID{1},
		Services: map[api.ServiceID]*api.Service{
			1: {
				Name:       "KeyValue",
				ThriftName: "KeyValue",
				Functions:  []*api.Function{},
				ModuleID:   api.ModuleID(1),
			},
		},
		Modules: map[api.ModuleID]*api.Module{
			1: {
				ImportPath: "go.uber.org/thriftrw/foo",
				Directory:  "foo",
			},
		},
	}

	for _, tt := range tests {
		func() {
			mockCtrl := gomock.NewController(t)
			defer mockCtrl.Finish()

			var msg MultiServiceGenerator
			for i, res := range tt.responses {
				handle := handletest.NewMockHandle(mockCtrl)
				handle.EXPECT().Name().Return(fmt.Sprintf("plugin-%d", i)).AnyTimes()

				sg := handletest.NewMockServiceGenerator(mockCtrl)
				msg = append(msg, sg)
				sg.EXPECT().Generate(req).Return(res.success, res.failure)
				sg.EXPECT().Handle().Return(handle).AnyTimes()
			}

			res, err := msg.Generate(req)
			if len(tt.wantErrors) > 0 || len(tt.wantOneOfErrors) > 0 {
				if !assert.Error(t, err, tt.desc) {
					return
				}

				for _, errMsg := range tt.wantErrors {
					assert.Contains(t, err.Error(), errMsg, tt.desc)
				}

				matches := len(tt.wantOneOfErrors) == 0
				for _, errMsg := range tt.wantOneOfErrors {
					if strings.Contains(err.Error(), errMsg) {
						matches = true
						break
					}
				}

				assert.True(t, matches, "expected %v to contain one of %v", err, tt.wantOneOfErrors)
			} else {
				assert.Equal(t, tt.wantResponse, res, tt.desc)
			}
		}()
	}
}
Ejemplo n.º 2
0
func TestServiceGeneratorGenerate(t *testing.T) {
	tests := []struct {
		desc             string
		generateResponse *api.GenerateServiceResponse
		generateError    error

		wantError string
	}{
		{
			desc: "success",
			generateResponse: &api.GenerateServiceResponse{
				Files: map[string][]byte{"foo/bar.go": []byte("package foo")},
			},
		},
		{
			desc: "parent directory",
			generateResponse: &api.GenerateServiceResponse{
				Files: map[string][]byte{"../foo/bar.go": []byte("package foo")},
			},
			wantError: `plugin "foo" is attempting to write to a parent directory: ` +
				`path "../foo/bar.go" contains ".."`,
		},
		{
			desc:          "call error",
			generateError: errors.New("great sadness"),
			wantError: `plugin "foo" failed to generate service code: ` +
				"TApplicationException{Message: great sadness, Type: INTERNAL_ERROR}",
		},
	}

	for _, tt := range tests {
		func() {
			mockCtrl := gomock.NewController(t)
			defer mockCtrl.Finish()

			server := newFakePluginServer(mockCtrl)
			defer server.Close()

			handle := server.Handshake(t, "foo", []api.Feature{api.FeatureServiceGenerator})
			defer func() {
				server.ExpectGoodbye()
				require.NoError(t, handle.Close(), tt.desc)
			}()

			req := &api.GenerateServiceRequest{
				RootServices: []api.ServiceID{1},
				Services: map[api.ServiceID]*api.Service{
					1: {
						Name:       "KeyValue",
						ThriftName: "KeyValue",
						Functions:  []*api.Function{},
						ModuleID:   api.ModuleID(1),
					},
				},
				Modules: map[api.ModuleID]*api.Module{
					1: {
						ImportPath: "go.uber.org/thriftrw/foo",
						Directory:  "foo",
					},
				},
			}

			server.ServiceGenerator.EXPECT().Generate(req).
				Return(tt.generateResponse, tt.generateError)

			res, err := handle.ServiceGenerator().Generate(req)
			if tt.wantError != "" {
				if assert.Error(t, err, tt.desc) {
					assert.Equal(t, tt.wantError, err.Error(), tt.desc)
				}
			} else {
				assert.NoError(t, err, tt.desc)
				assert.Equal(t, tt.generateResponse, res, tt.desc)
			}
		}()
	}
}