File size: 3,753 Bytes
6a7089a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package orchestrator

import (
	"fmt"
	"io"
	"net"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/pinchtab/pinchtab/internal/bridge"
)

func startLocalHTTPServer(t *testing.T, h http.Handler) (*httptest.Server, string) {
	t.Helper()
	ln, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		t.Fatalf("listen: %v", err)
	}
	server := httptest.NewUnstartedServer(h)
	server.Listener = ln
	server.Start()
	return server, fmt.Sprintf("%d", ln.Addr().(*net.TCPAddr).Port)
}

func TestProxyTabRequest_FallsBackToOnlyRunningInstance(t *testing.T) {
	backend, port := startLocalHTTPServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		_, _ = io.WriteString(w, `{"ok":true}`)
	}))
	defer backend.Close()

	o := NewOrchestrator(t.TempDir())
	o.client = backend.Client()
	o.instances["inst_1"] = &InstanceInternal{
		Instance: bridge.Instance{ID: "inst_1", Status: "running", Port: port},
		URL:      "http://localhost:" + port,
		cmd:      &mockCmd{pid: 1234, isAlive: true},
	}

	req := httptest.NewRequest(http.MethodGet, "/tabs/ABC123/snapshot", nil)
	req.SetPathValue("id", "ABC123")
	w := httptest.NewRecorder()

	orig := processAliveFunc
	processAliveFunc = func(pid int) bool { return true }
	defer func() { processAliveFunc = orig }()

	o.proxyTabRequest(w, req)

	resp := w.Result()
	if resp.StatusCode != http.StatusOK {
		t.Fatalf("status = %d, want 200", resp.StatusCode)
	}
}

func TestSingleRunningInstance_MultipleInstancesReturnsNil(t *testing.T) {
	o := NewOrchestrator(t.TempDir())
	o.instances["inst_1"] = &InstanceInternal{Instance: bridge.Instance{ID: "inst_1", Status: "running"}, cmd: &mockCmd{pid: 1, isAlive: true}}
	o.instances["inst_2"] = &InstanceInternal{Instance: bridge.Instance{ID: "inst_2", Status: "running"}, cmd: &mockCmd{pid: 2, isAlive: true}}

	orig := processAliveFunc
	processAliveFunc = func(pid int) bool { return true }
	defer func() { processAliveFunc = orig }()

	if got := o.singleRunningInstance(); got != nil {
		t.Fatalf("expected nil, got %v", got.ID)
	}
}

func TestSingleRunningInstance_IgnoresStopped(t *testing.T) {
	o := NewOrchestrator(t.TempDir())
	o.instances["inst_1"] = &InstanceInternal{Instance: bridge.Instance{ID: "inst_1", Status: "running"}, cmd: &mockCmd{pid: 1, isAlive: true}}
	o.instances["inst_2"] = &InstanceInternal{Instance: bridge.Instance{ID: "inst_2", Status: "stopped"}}

	orig := processAliveFunc
	processAliveFunc = func(pid int) bool { return pid == 1 }
	defer func() { processAliveFunc = orig }()

	got := o.singleRunningInstance()
	if got == nil || got.ID != "inst_1" {
		t.Fatalf("got %#v, want inst_1", got)
	}
}

func TestProxyToURL_UsesAttachedBridgeOriginAndAuth(t *testing.T) {
	backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if got := r.Header.Get("Authorization"); got != "Bearer bridge-token" {
			t.Fatalf("authorization = %q, want %q", got, "Bearer bridge-token")
		}
		if r.URL.Path != "/tabs/tab-1/snapshot" {
			t.Fatalf("path = %q", r.URL.Path)
		}
		_, _ = io.WriteString(w, `ok`)
	}))
	defer backend.Close()

	o := NewOrchestrator(t.TempDir())
	o.client = backend.Client()
	attached, err := o.AttachBridge("bridge1", backend.URL, "bridge-token")
	if err != nil {
		t.Fatalf("AttachBridge failed: %v", err)
	}

	req := httptest.NewRequest(http.MethodGet, "/tabs/tab-1/snapshot", nil)
	req.SetPathValue("id", "tab-1")
	w := httptest.NewRecorder()

	targetURL, err := o.instancePathURLFromBridge(attached, "/tabs/tab-1/snapshot", "")
	if err != nil {
		t.Fatalf("instancePathURLFromBridge failed: %v", err)
	}
	o.proxyToURL(w, req, targetURL)

	if w.Code != http.StatusOK {
		t.Fatalf("status = %d, want 200", w.Code)
	}
}