Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tests for file dynamic file updats and cleaned up documentation #3

Merged
merged 2 commits into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions cmd/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,15 @@ func formatCommandDescriptions() string {
return buf.String()
}

const usage = `== Web Development 40 ==
const usage = `== Web Development 41 ==

This tool is designed to enable hot reload for any statically hosted web development.
It injects a websocket script (in a mirrored version of the file) into html pages
This tool is designed to enable live reload for statically hosted web development.
It injects a websocket script in a mirrored version of html pages
and uses the fsnotify (cross-platform 'inotify' wrapper) package to detect filechanges.
On filechanges, the websocket will trigger a reload of the page.

The 40 is only to enable rust-repellant properties.
The 41 (formerly "40", before I got spooked by potential lawyers) is only
to enable rust-repellant properties.

Commands:
%v`
Expand Down
106 changes: 106 additions & 0 deletions internal/wsinject/wsinject_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
package wsinject

import (
"context"
"fmt"
"os"
"path"
"path/filepath"
"slices"
"strings"
"testing"
"time"

"github.com/baalimago/go_away_boilerplate/pkg/ancli"
"github.com/baalimago/go_away_boilerplate/pkg/testboil"
)

func Test_walkDir(t *testing.T) {
Expand Down Expand Up @@ -111,3 +116,104 @@ func Test_Setup(t *testing.T) {
checkIfDeltaStreamerExists(t, mirrorFilePath)
})
}

type testFileSystem struct {
root string
rootDirFilePaths []string
nestedDir string
}

func (tfs *testFileSystem) addRootFile(t *testing.T, suffix string) string {
t.Helper()
fileName := fmt.Sprintf("file_%v%v", len(tfs.rootDirFilePaths), suffix)
path := path.Join(tfs.root, fileName)
err := os.WriteFile(path, []byte(mockHtml), 0o777)
if err != nil {
t.Fatalf("failed to write root file: %v", err)
}
tfs.rootDirFilePaths = append(tfs.rootDirFilePaths, path)
return path
}

func Test_Start(t *testing.T) {
setup := func(t *testing.T) (*Fileserver, testFileSystem) {
t.Helper()
tmpDir := t.TempDir()
ancli.Newline = true
nestedDir := path.Join(tmpDir, "nested")
err := os.MkdirAll(nestedDir, 0o777)
if err != nil {
t.Fatalf("failed to create temp dir: %v", err)
}
return NewFileServer(8080, "/delta-streamer-ws.js"), testFileSystem{
root: tmpDir,
nestedDir: nestedDir,
}
}

t.Run("it should break on context cancel", func(t *testing.T) {
fs, _ := setup(t)
_, err := fs.Setup(t.TempDir())
if err != nil {
t.Fatalf("failed ot setup test fileserver: %v", err)
}
testboil.ReturnsOnContextCancel(t, func(ctx context.Context) {
fs.Start(ctx)
}, time.Second)
})

t.Run("file changes", func(t *testing.T) {
setupReadyFs := func(t *testing.T) (testFileSystem, chan error, chan string, context.Context) {
t.Helper()
fs, testFileSystem := setup(t)
testFileSystem.addRootFile(t, "")
fs.Setup(testFileSystem.root)
refreshChan := make(chan string)
fs.registerWs("mock", refreshChan)
timeoutCtx, cancel := context.WithTimeout(context.Background(), time.Second)
t.Cleanup(cancel)
earlyFail := make(chan error, 1)
awaitFsStart := make(chan struct{})
go func() {
close(awaitFsStart)
err := fs.Start(timeoutCtx)
if err != nil {
earlyFail <- err
}
}()

<-awaitFsStart
// Give the Start a moment to actually start, not just the routine
time.Sleep(time.Millisecond)
return testFileSystem, earlyFail, refreshChan, timeoutCtx
}

t.Run("it should send a reload event on file changes", func(t *testing.T) {
testFileSystem, earlyFail, refreshChan, timeoutCtx := setupReadyFs(t)
testFile := testFileSystem.rootDirFilePaths[0]
os.WriteFile(testFile, []byte("changes!"), 0o755)

select {
case err := <-earlyFail:
t.Fatalf("start failed: %v", err)
case got := <-refreshChan:
testboil.FailTestIfDiff(t, got, "/"+filepath.Base(testFile))
case <-timeoutCtx.Done():
t.Fatal("failed to recieve refresh within time")
}
})

t.Run("it should send a reload event on file additions", func(t *testing.T) {
testFileSystem, earlyFail, refreshChan, timeoutCtx := setupReadyFs(t)
testFile := testFileSystem.addRootFile(t, "")
select {
case err := <-earlyFail:
t.Fatalf("start failed: %v", err)
case got := <-refreshChan:
testboil.FailTestIfDiff(t, got, "/"+filepath.Base(testFile))
case <-timeoutCtx.Done():
t.Fatal("failed to recieve refresh within time")
}
})
})
}
Loading