Skip to content

Commit

Permalink
fix(#77): stdin redirect (#78)
Browse files Browse the repository at this point in the history
  • Loading branch information
hedhyw authored Jun 2, 2024
1 parent 041a4d6 commit a781d18
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 6 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ jlv << EOF
EOF

kubectl logs pod/POD_NAME -f | jlv
docker logs 000000000000 | jlv
docker logs -f 000000000000 2>&1 | jlv
```

### Hotkeys
Expand Down
11 changes: 6 additions & 5 deletions cmd/jlv/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
"flag"
"fmt"
"io/fs"
"os"
"path"

Expand Down Expand Up @@ -42,7 +43,7 @@ func main() {

switch flag.NArg() {
case 0:
sourceInput, err = getStdinSource(cfg)
sourceInput, err = getStdinSource(cfg, os.Stdin)
if err != nil {
fatalf("Stdin: %s\n", err)
}
Expand All @@ -60,17 +61,17 @@ func main() {
}
}

func getStdinSource(cfg *config.Config) (source.Input, error) {
stat, err := os.Stdin.Stat()
func getStdinSource(cfg *config.Config, defaultInput fs.File) (source.Input, error) {
stat, err := defaultInput.Stat()
if err != nil {
return nil, fmt.Errorf("stat: %w", err)
}

if stat.Mode()&os.ModeNamedPipe == 0 {
if stat.Mode()&os.ModeCharDevice != 0 {
return readerinput.New(bytes.NewReader(nil), cfg.StdinReadTimeout), nil
}

return readerinput.New(os.Stdin, cfg.StdinReadTimeout), nil
return readerinput.New(defaultInput, cfg.StdinReadTimeout), nil
}

func fatalf(message string, args ...any) {
Expand Down
106 changes: 106 additions & 0 deletions cmd/jlv/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package main

import (
"bytes"
"context"
"errors"
"io"
"io/fs"
"os"
"testing"

"github.com/hedhyw/json-log-viewer/internal/pkg/config"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestGetStdinSource(t *testing.T) {
t.Parallel()

ctx := context.Background()

t.Run("ModeNamedPipe", func(t *testing.T) {
t.Parallel()

content := t.Name() + "\n"

file := fakeFile{
Reader: bytes.NewReader([]byte(content)),
StatFileInfo: fakeFileInfo{
FileMode: os.ModeNamedPipe,
},
}

input, err := getStdinSource(config.GetDefaultConfig(), file)
require.NoError(t, err)

readCloser, err := input.ReadCloser(ctx)
require.NoError(t, err)

t.Cleanup(func() { assert.NoError(t, readCloser.Close()) })

data, err := io.ReadAll(readCloser)
require.NoError(t, err)
assert.Equal(t, content, string(data))
})

t.Run("ModeCharDevice", func(t *testing.T) {
t.Parallel()

file := fakeFile{
Reader: bytes.NewReader([]byte(t.Name() + "\n")),
StatFileInfo: fakeFileInfo{
FileMode: os.ModeCharDevice,
},
}

input, err := getStdinSource(config.GetDefaultConfig(), file)
require.NoError(t, err)

readCloser, err := input.ReadCloser(ctx)
require.NoError(t, err)

t.Cleanup(func() { assert.NoError(t, readCloser.Close()) })

data, err := io.ReadAll(readCloser)
require.NoError(t, err)
assert.Empty(t, data)
})

t.Run("Stat_error", func(t *testing.T) {
t.Parallel()

// nolint: err113 // Test.
errStat := errors.New(t.Name())

file := fakeFile{ErrStat: errStat}

_, err := getStdinSource(config.GetDefaultConfig(), file)
require.Error(t, err)
require.ErrorIs(t, err, errStat)
})
}

type fakeFile struct {
io.Closer
io.Reader

StatFileInfo os.FileInfo
ErrStat error
}

// Stat implements fs.File.
func (f fakeFile) Stat() (os.FileInfo, error) {
return f.StatFileInfo, f.ErrStat
}

type fakeFileInfo struct {
fs.FileInfo
FileMode fs.FileMode
}

// Mode implements fs.FileInfo.
func (f fakeFileInfo) Mode() fs.FileMode {
return f.FileMode
}

0 comments on commit a781d18

Please sign in to comment.