Skip to content

Commit

Permalink
Merge pull request #499 from mesg-foundation/feature/service-list
Browse files Browse the repository at this point in the history
extend ListServices api to filter by running services, closes #496
  • Loading branch information
antho1404 authored Oct 3, 2018
2 parents fe98a41 + 0f1199f commit 0f695e6
Show file tree
Hide file tree
Showing 14 changed files with 326 additions and 144 deletions.
2 changes: 1 addition & 1 deletion api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ func New(db *database.ServiceDB, options ...Option) (*API, error) {
for _, option := range options {
option(a)
}
var err error
if a.container == nil {
var err error
a.container, err = container.New()
if err != nil {
return nil, err
Expand Down
2 changes: 2 additions & 0 deletions api/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ func (l *serviceLister) List() ([]*service.Service, error) {
if err != nil {
return nil, err
}

var services []*service.Service
for _, s := range ss {
s, err = service.FromService(s, service.ContainerOption(l.api.container))
Expand All @@ -42,5 +43,6 @@ func (l *serviceLister) List() ([]*service.Service, error) {
}
services = append(services, s)
}

return services, nil
}
7 changes: 6 additions & 1 deletion commands/commands_mock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,14 @@ import (
"github.com/stretchr/testify/require"
)

var (
_ RootExecutor = (*mockRootExecutor)(nil)
_ ServiceExecutor = (*mockServiceExecutor)(nil)
)

// captureStd is helper function that captures Stdout and Stderr and returns function
// that returns standard output and standard error as string.
func captureStd(t *testing.T) func() (string, string) {
func captureStd(t *testing.T) func() (stdout string, stderr string) {
var (
bufout strings.Builder
buferr strings.Builder
Expand Down
18 changes: 12 additions & 6 deletions commands/provider/core_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package provider
import (
"context"
"io"
"sync"

"github.com/mesg-foundation/core/container"
"github.com/mesg-foundation/core/daemon"
Expand Down Expand Up @@ -39,23 +40,28 @@ func (p *CoreProvider) Stop() error {
var (
idsLen = len(ids)
errC = make(chan error, idsLen)
wg sync.WaitGroup
)

wg.Add(idsLen)
for _, id := range ids {
go func(id string) {
defer wg.Done()
_, err := p.client.StopService(context.Background(), &coreapi.StopServiceRequest{
ServiceID: id,
})
errC <- err
if err != nil {
errC <- err
}
}(id)
}

var errs xerrors.Errors
wg.Wait()
close(errC)

for i := 0; i < idsLen; i++ {
if err := <-errC; err != nil {
errs = append(errs, err)
}
var errs xerrors.Errors
for err := range errC {
errs = append(errs, err)
}

if err := daemon.Stop(); err != nil {
Expand Down
15 changes: 5 additions & 10 deletions commands/service_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package commands
import (
"fmt"
"os"
"strings"
"text/tabwriter"

"github.com/mesg-foundation/core/protobuf/coreapi"
Expand All @@ -16,6 +17,7 @@ type serviceListCmd struct {
e ServiceExecutor
}

// newServiceListCmd receives e to do API calls and w to output structured table logs.
func newServiceListCmd(e ServiceExecutor) *serviceListCmd {
c := &serviceListCmd{e: e}
c.cmd = newCommand(&cobra.Command{
Expand Down Expand Up @@ -44,18 +46,11 @@ func (c *serviceListCmd) runE(cmd *cobra.Command, args []string) error {
}

w := tabwriter.NewWriter(os.Stdout, 0, 0, 4, ' ', 0)
fmt.Fprintf(w, "SERVICE\tNAME\n")

// TODO: implement status to ServiceList API.
//fmt.Fprintf(w, "STATUS\tSERVICE\tNAME\n")
fmt.Fprintf(w, "STATUS\tSERVICE\tNAME\t\n")
for _, s := range services {
// status, err := s.Status()
// if err != nil {
// return err
// }

fmt.Fprintf(w, "%s\t%s\n", s.ID, s.Name)
//fmt.Fprintf(w, "%s\t%s\t%s\n", status.String(), s.ID, s.Name)
status := strings.ToLower(s.Status.String())
fmt.Fprintf(w, "%s\t%s\t%s\t\n", status, s.ID, s.Name)
}
return w.Flush()
}
53 changes: 53 additions & 0 deletions commands/service_list_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package commands

import (
"bufio"
"fmt"
"regexp"
"strings"
"testing"

"github.com/mesg-foundation/core/protobuf/coreapi"
"github.com/stretchr/testify/require"
)

func TestServiceList(t *testing.T) {
var (
services = []*coreapi.Service{
{ID: "1", Name: "a", Status: coreapi.Service_RUNNING},
{ID: "2", Name: "b", Status: coreapi.Service_PARTIAL},
}
m = newMockExecutor()
c = newServiceListCmd(m)
)

m.On("ServiceList").Return(services, nil)

closeStd := captureStd(t)
c.cmd.Execute()
stdout, _ := closeStd()
r := bufio.NewReader(strings.NewReader(stdout))

for _, s := range []string{
`Listing services\.\.\.`,
`STATUS\s+SERVICE\s+NAME`,
} {
matched, err := regexp.Match(fmt.Sprintf(`^\s*%s\s*$`, s), readLine(t, r))
require.NoError(t, err)
require.True(t, matched)
}

for _, s := range services {
status := strings.ToLower(s.Status.String())
pattern := fmt.Sprintf(`^\s*%s\s+%s\s+%s\s*$`, status, s.ID, s.Name)
matched, err := regexp.Match(pattern, readLine(t, r))
require.NoError(t, err)
require.True(t, matched)
}
}

func readLine(t *testing.T, r *bufio.Reader) []byte {
line, _, err := r.ReadLine()
require.NoError(t, err)
return line
}
15 changes: 15 additions & 0 deletions interface/grpc/core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,21 @@ func toProtoService(s *service.Service) *coreapi.Service {
}
}

func toProtoServiceStatusType(s service.StatusType) coreapi.Service_Status {
switch s {
default:
return coreapi.Service_UNKNOWN
case service.STOPPED:
return coreapi.Service_STOPPED
case service.STARTING:
return coreapi.Service_STARTING
case service.PARTIAL:
return coreapi.Service_PARTIAL
case service.RUNNING:
return coreapi.Service_RUNNING
}
}

func toProtoTasks(tasks []*service.Task) []*coreapi.Task {
ts := make([]*coreapi.Task, 0)
for _, task := range tasks {
Expand Down
10 changes: 8 additions & 2 deletions interface/grpc/core/get_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,15 @@ import (

// GetService returns service serviceID.
func (s *Server) GetService(ctx context.Context, request *coreapi.GetServiceRequest) (*coreapi.GetServiceReply, error) {
srv, err := s.api.GetService(request.ServiceID)
ss, err := s.api.GetService(request.ServiceID)
if err != nil {
return nil, err
}
return &coreapi.GetServiceReply{Service: toProtoService(srv)}, nil
protoService := toProtoService(ss)
status, err := ss.Status()
if err != nil {
return nil, err
}
protoService.Status = toProtoServiceStatusType(status)
return &coreapi.GetServiceReply{Service: protoService}, nil
}
40 changes: 39 additions & 1 deletion interface/grpc/core/list_services.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ package core

import (
"context"
"sync"

"github.com/mesg-foundation/core/protobuf/coreapi"
"github.com/mesg-foundation/core/service"
"github.com/mesg-foundation/core/x/xerrors"
)

// ListServices lists services.
Expand All @@ -12,5 +15,40 @@ func (s *Server) ListServices(ctx context.Context, request *coreapi.ListServices
if err != nil {
return nil, err
}
return &coreapi.ListServicesReply{Services: toProtoServices(services)}, nil

var (
protoServices []*coreapi.Service
mp sync.Mutex

servicesLen = len(services)
errC = make(chan error, servicesLen)
wg sync.WaitGroup
)

wg.Add(servicesLen)
for _, s := range services {
go func(s *service.Service) {
defer wg.Done()
status, err := s.Status()
if err != nil {
errC <- err
return
}
protoService := toProtoService(s)
protoService.Status = toProtoServiceStatusType(status)
mp.Lock()
protoServices = append(protoServices, protoService)
mp.Unlock()
}(s)
}

wg.Wait()
close(errC)

var errs xerrors.Errors
for err := range errC {
errs = append(errs, err)
}

return &coreapi.ListServicesReply{Services: protoServices}, errs.ErrorOrNil()
}
10 changes: 9 additions & 1 deletion interface/grpc/core/list_services_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,22 @@ import (
)

func TestListServices(t *testing.T) {
url := "https://github.com/mesg-foundation/service-webhook"
server, closer := newServer(t)
defer closer()

stream := newTestDeployStream(url)
require.NoError(t, server.DeployService(stream))
defer server.api.DeleteService(stream.serviceID)

reply, err := server.ListServices(context.Background(), &coreapi.ListServicesRequest{})
require.NoError(t, err)

services, err := server.api.ListServices()
require.NoError(t, err)

require.Equal(t, toProtoServices(services), reply.Services)
apiProtoServices := toProtoServices(services)

require.Len(t, apiProtoServices, 1)
require.Equal(t, reply.Services[0].ID, apiProtoServices[0].ID)
}
1 change: 1 addition & 0 deletions interface/grpc/service/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ var (
func newServer(t *testing.T) (*Server, func()) {
db, err := database.NewServiceDB("db.test")
require.NoError(t, err)

a, err := api.New(db)
require.Nil(t, err)

Expand Down
Loading

0 comments on commit 0f695e6

Please sign in to comment.