github.com/anuvu/nomad@v0.8.7-atom1/api/fs_test.go (about)

     1  package api
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"reflect"
     8  	"strings"
     9  	"testing"
    10  	"time"
    11  
    12  	units "github.com/docker/go-units"
    13  	"github.com/hashicorp/nomad/helper"
    14  	"github.com/hashicorp/nomad/testutil"
    15  	"github.com/kr/pretty"
    16  	"github.com/stretchr/testify/assert"
    17  	"github.com/stretchr/testify/require"
    18  )
    19  
    20  func TestFS_Logs(t *testing.T) {
    21  	t.Parallel()
    22  	require := require.New(t)
    23  	rpcPort := 0
    24  	c, s := makeClient(t, nil, func(c *testutil.TestServerConfig) {
    25  		rpcPort = c.Ports.RPC
    26  		c.Client = &testutil.ClientConfig{
    27  			Enabled: true,
    28  		}
    29  	})
    30  	defer s.Stop()
    31  
    32  	//TODO There should be a way to connect the client to the servers in
    33  	//makeClient above
    34  	require.NoError(c.Agent().SetServers([]string{fmt.Sprintf("127.0.0.1:%d", rpcPort)}))
    35  
    36  	index := uint64(0)
    37  	testutil.WaitForResult(func() (bool, error) {
    38  		nodes, qm, err := c.Nodes().List(&QueryOptions{WaitIndex: index})
    39  		if err != nil {
    40  			return false, err
    41  		}
    42  		index = qm.LastIndex
    43  		if len(nodes) != 1 {
    44  			return false, fmt.Errorf("expected 1 node but found: %s", pretty.Sprint(nodes))
    45  		}
    46  		if nodes[0].Status != "ready" {
    47  			return false, fmt.Errorf("node not ready: %s", nodes[0].Status)
    48  		}
    49  		return true, nil
    50  	}, func(err error) {
    51  		t.Fatalf("err: %v", err)
    52  	})
    53  
    54  	var input strings.Builder
    55  	input.Grow(units.MB)
    56  	lines := 80 * units.KB
    57  	for i := 0; i < lines; i++ {
    58  		fmt.Fprintf(&input, "%d\n", i)
    59  	}
    60  
    61  	job := &Job{
    62  		ID:          helper.StringToPtr("TestFS_Logs"),
    63  		Region:      helper.StringToPtr("global"),
    64  		Datacenters: []string{"dc1"},
    65  		Type:        helper.StringToPtr("batch"),
    66  		TaskGroups: []*TaskGroup{
    67  			{
    68  				Name: helper.StringToPtr("TestFS_LogsGroup"),
    69  				Tasks: []*Task{
    70  					{
    71  						Name:   "logger",
    72  						Driver: "mock_driver",
    73  						Config: map[string]interface{}{
    74  							"stdout_string": input.String(),
    75  						},
    76  					},
    77  				},
    78  			},
    79  		},
    80  	}
    81  
    82  	jobs := c.Jobs()
    83  	jobResp, _, err := jobs.Register(job, nil)
    84  	require.NoError(err)
    85  
    86  	index = jobResp.EvalCreateIndex
    87  	evals := c.Evaluations()
    88  	testutil.WaitForResult(func() (bool, error) {
    89  		evalResp, qm, err := evals.Info(jobResp.EvalID, &QueryOptions{WaitIndex: index})
    90  		if err != nil {
    91  			return false, err
    92  		}
    93  		if evalResp.BlockedEval != "" {
    94  			t.Fatalf("Eval blocked: %s", pretty.Sprint(evalResp))
    95  		}
    96  		index = qm.LastIndex
    97  		if evalResp.Status != "complete" {
    98  			return false, fmt.Errorf("eval status: %v", evalResp.Status)
    99  		}
   100  		return true, nil
   101  	}, func(err error) {
   102  		t.Fatalf("err: %v", err)
   103  	})
   104  
   105  	allocID := ""
   106  	testutil.WaitForResult(func() (bool, error) {
   107  		allocs, _, err := jobs.Allocations(*job.ID, true, &QueryOptions{WaitIndex: index})
   108  		if err != nil {
   109  			return false, err
   110  		}
   111  		if len(allocs) != 1 {
   112  			return false, fmt.Errorf("unexpected number of allocs: %d", len(allocs))
   113  		}
   114  		if allocs[0].ClientStatus != "complete" {
   115  			return false, fmt.Errorf("alloc not complete: %s", allocs[0].ClientStatus)
   116  		}
   117  		allocID = allocs[0].ID
   118  		return true, nil
   119  	}, func(err error) {
   120  		t.Fatalf("err: %v", err)
   121  	})
   122  
   123  	alloc, _, err := c.Allocations().Info(allocID, nil)
   124  	require.NoError(err)
   125  
   126  	for i := 0; i < 3; i++ {
   127  		stopCh := make(chan struct{})
   128  		defer close(stopCh)
   129  
   130  		frames, errors := c.AllocFS().Logs(alloc, false, "logger", "stdout", "start", 0, stopCh, nil)
   131  
   132  		var result bytes.Buffer
   133  	READ_FRAMES:
   134  		for {
   135  			select {
   136  			case f := <-frames:
   137  				if f == nil {
   138  					break READ_FRAMES
   139  				}
   140  				result.Write(f.Data)
   141  			case err := <-errors:
   142  				// Don't Fatal here as the other assertions may
   143  				// contain helpeful information.
   144  				t.Errorf("Error: %v", err)
   145  			}
   146  		}
   147  
   148  		// Check length
   149  		assert.Equal(t, input.Len(), result.Len(), "file size mismatch")
   150  
   151  		// Check complete ordering
   152  		for i := 0; i < lines; i++ {
   153  			line, err := result.ReadBytes('\n')
   154  			require.NoErrorf(err, "unexpected error on line %d: %v", i, err)
   155  			require.Equal(fmt.Sprintf("%d\n", i), string(line))
   156  		}
   157  	}
   158  }
   159  
   160  func TestFS_FrameReader(t *testing.T) {
   161  	t.Parallel()
   162  	// Create a channel of the frames and a cancel channel
   163  	framesCh := make(chan *StreamFrame, 3)
   164  	errCh := make(chan error)
   165  	cancelCh := make(chan struct{})
   166  
   167  	r := NewFrameReader(framesCh, errCh, cancelCh)
   168  
   169  	// Create some frames and send them
   170  	f1 := &StreamFrame{
   171  		File:   "foo",
   172  		Offset: 5,
   173  		Data:   []byte("hello"),
   174  	}
   175  	f2 := &StreamFrame{
   176  		File:   "foo",
   177  		Offset: 10,
   178  		Data:   []byte(", wor"),
   179  	}
   180  	f3 := &StreamFrame{
   181  		File:   "foo",
   182  		Offset: 12,
   183  		Data:   []byte("ld"),
   184  	}
   185  	framesCh <- f1
   186  	framesCh <- f2
   187  	framesCh <- f3
   188  	close(framesCh)
   189  
   190  	expected := []byte("hello, world")
   191  
   192  	// Read a little
   193  	p := make([]byte, 12)
   194  
   195  	n, err := r.Read(p[:5])
   196  	if err != nil {
   197  		t.Fatalf("Read failed: %v", err)
   198  	}
   199  	if off := r.Offset(); off != n {
   200  		t.Fatalf("unexpected read bytes: got %v; wanted %v", n, off)
   201  	}
   202  
   203  	off := n
   204  	for {
   205  		n, err = r.Read(p[off:])
   206  		if err != nil {
   207  			if err == io.EOF {
   208  				break
   209  			}
   210  			t.Fatalf("Read failed: %v", err)
   211  		}
   212  		off += n
   213  	}
   214  
   215  	if !reflect.DeepEqual(p, expected) {
   216  		t.Fatalf("read %q, wanted %q", string(p), string(expected))
   217  	}
   218  
   219  	if err := r.Close(); err != nil {
   220  		t.Fatalf("Close() failed: %v", err)
   221  	}
   222  	if _, ok := <-cancelCh; ok {
   223  		t.Fatalf("Close() didn't close cancel channel")
   224  	}
   225  	if len(expected) != r.Offset() {
   226  		t.Fatalf("offset %d, wanted %d", r.Offset(), len(expected))
   227  	}
   228  }
   229  
   230  func TestFS_FrameReader_Unblock(t *testing.T) {
   231  	t.Parallel()
   232  	// Create a channel of the frames and a cancel channel
   233  	framesCh := make(chan *StreamFrame, 3)
   234  	errCh := make(chan error)
   235  	cancelCh := make(chan struct{})
   236  
   237  	r := NewFrameReader(framesCh, errCh, cancelCh)
   238  	r.SetUnblockTime(10 * time.Millisecond)
   239  
   240  	// Read a little
   241  	p := make([]byte, 12)
   242  
   243  	n, err := r.Read(p)
   244  	if err != nil {
   245  		t.Fatalf("Read failed: %v", err)
   246  	}
   247  
   248  	if n != 0 {
   249  		t.Fatalf("should have unblocked")
   250  	}
   251  
   252  	// Unset the unblock
   253  	r.SetUnblockTime(0)
   254  
   255  	resultCh := make(chan struct{})
   256  	go func() {
   257  		r.Read(p)
   258  		close(resultCh)
   259  	}()
   260  
   261  	select {
   262  	case <-resultCh:
   263  		t.Fatalf("shouldn't have unblocked")
   264  	case <-time.After(300 * time.Millisecond):
   265  	}
   266  }
   267  
   268  func TestFS_FrameReader_Error(t *testing.T) {
   269  	t.Parallel()
   270  	// Create a channel of the frames and a cancel channel
   271  	framesCh := make(chan *StreamFrame, 3)
   272  	errCh := make(chan error, 1)
   273  	cancelCh := make(chan struct{})
   274  
   275  	r := NewFrameReader(framesCh, errCh, cancelCh)
   276  	r.SetUnblockTime(10 * time.Millisecond)
   277  
   278  	// Send an error
   279  	expected := fmt.Errorf("test error")
   280  	errCh <- expected
   281  
   282  	// Read a little
   283  	p := make([]byte, 12)
   284  
   285  	_, err := r.Read(p)
   286  	if err == nil || !strings.Contains(err.Error(), expected.Error()) {
   287  		t.Fatalf("bad error: %v", err)
   288  	}
   289  }