mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-15 04:53:00 +08:00
138 lines
5.1 KiB
Go
138 lines
5.1 KiB
Go
//go:build unix
|
|
|
|
package daemon
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/matthewlu070111/smart-srun/core/internal/application"
|
|
"github.com/matthewlu070111/smart-srun/core/internal/config"
|
|
"github.com/matthewlu070111/smart-srun/core/internal/domain"
|
|
"github.com/matthewlu070111/smart-srun/core/internal/portal"
|
|
"github.com/matthewlu070111/smart-srun/core/internal/presets"
|
|
)
|
|
|
|
func TestEnvironmentJobWithoutAddressIsAsyncSessionBoundAndReadOnly(t *testing.T) {
|
|
entered, proceed := make(chan struct{}), make(chan struct{})
|
|
release := sync.OnceFunc(func() { close(proceed) })
|
|
defer release()
|
|
service := start(t, func(o *Options) {
|
|
o.ProbeGateways = func(_ context.Context, iface string) ([]string, error) {
|
|
if iface != "wan" {
|
|
t.Error("wrong gateway interface")
|
|
}
|
|
return []string{"http://gateway.invalid/full/login?theme=pro"}, nil
|
|
}
|
|
o.OpenProbe = func(_ context.Context, iface string) (portal.Fetcher, func(), error) {
|
|
if iface != "wan" {
|
|
t.Error("wrong client interface")
|
|
}
|
|
return probeFunc(func(r *http.Request) (*http.Response, error) {
|
|
if r.Header.Get("Authorization") != "" || r.Header.Get("Cookie") != "" {
|
|
t.Error("credentials sent")
|
|
}
|
|
if r.URL.Host == "gateway.invalid" {
|
|
if r.URL.RequestURI() != "/full/login?theme=pro" {
|
|
t.Error("lost full path")
|
|
}
|
|
close(entered)
|
|
select {
|
|
case <-proceed:
|
|
case <-r.Context().Done():
|
|
return nil, r.Context().Err()
|
|
}
|
|
return &http.Response{StatusCode: 200, Header: http.Header{}, Body: io.NopCloser(strings.NewReader(`<input name="ac_id" value="007">`))}, nil
|
|
}
|
|
return &http.Response{StatusCode: 204, Header: http.Header{}, Body: io.NopCloser(strings.NewReader(""))}, nil
|
|
}), func() {}, nil
|
|
}
|
|
})
|
|
params := DetectACIDParams{Iface: "wan", AccessMode: "wired", IdempotencyKey: "environment", Session: "owner"}
|
|
var receipt SubmitResult
|
|
if err := json.Unmarshal(service.call("detect.environment", params), &receipt); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
select {
|
|
case <-entered:
|
|
case <-time.After(patience):
|
|
t.Fatal("worker did not start")
|
|
}
|
|
if service.status().Service != ServiceRunning {
|
|
t.Fatal("status stalled")
|
|
}
|
|
var retry SubmitResult
|
|
json.Unmarshal(service.call("detect.environment", params), &retry)
|
|
if !retry.Duplicate || retry.ActionID != receipt.ActionID {
|
|
t.Fatal("duplicate not deduplicated")
|
|
}
|
|
if codeOf(t, service.callExpectingError("action.get", ActionParams{ActionID: receipt.ActionID, Session: "other"})) != domain.CodeNotFound {
|
|
t.Fatal("session leak")
|
|
}
|
|
release()
|
|
if action := service.awaitTerminal(receipt.ActionID); action.State != application.StateSucceeded {
|
|
t.Fatalf("%+v", action)
|
|
}
|
|
var result struct {
|
|
Result DetectEnvironmentResult `json:"result"`
|
|
}
|
|
json.Unmarshal(service.call("action.get", ActionParams{ActionID: receipt.ActionID, Session: "owner"}), &result)
|
|
if !result.Result.OK || result.Result.State != "online" || result.Result.ACID != "007" || result.Result.AddressSource != "所选出口的网关" {
|
|
t.Fatalf("%+v", result)
|
|
}
|
|
if _, err := os.Stat(service.paths.ConfigFile()); !os.IsNotExist(err) {
|
|
t.Fatal("discovery wrote config")
|
|
}
|
|
params.Iface, params.IdempotencyKey = "", "missing-line"
|
|
if codeOf(t, service.callExpectingError("detect.environment", params)) != domain.CodeInvalidArgument {
|
|
t.Fatal("missing line accepted")
|
|
}
|
|
}
|
|
|
|
func TestEnvironmentCandidatesExcludeOtherLinesAndCredentials(t *testing.T) {
|
|
repo, err := config.Open(t.TempDir() + "/config.json")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// Use the public repository mutation path to keep this fixture realistic.
|
|
d := &Daemon{config: repo, users: presets.NewUserStore(t.TempDir() + "/users.json"),
|
|
publicPresets: func() ([]presets.School, error) {
|
|
return []presets.School{{ShortName: "chosen", Defaults: presets.Defaults{BaseURL: "http://school.invalid/full"}}}, nil
|
|
},
|
|
probeGateways: func(_ context.Context, iface string) ([]string, error) {
|
|
return []string{"http://gateway.invalid"}, nil
|
|
},
|
|
}
|
|
// Stored account passwords never enter a candidate; only matching lines do.
|
|
service := start(t, nil)
|
|
for i, a := range []string{
|
|
`{"user_id":"other","password":"private-password","access_mode":"wired","wired_iface":"wan2","base_url":"http://other.invalid"}`,
|
|
`{"user_id":"student","password":"private-password","access_mode":"wired","wired_iface":"wan","base_url":"http://saved.invalid"}`,
|
|
`{"user_id":"wifi","access_mode":"wifi","ssid":"campus","base_url":"http://wifi.invalid"}`,
|
|
} {
|
|
service.writeConfig("campus.upsert", fmt.Sprintf(`{"expected_revision":%d,"account":%s}`, i, a))
|
|
}
|
|
d.config, err = config.Open(service.paths.ConfigFile())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
candidates := d.environmentCandidates(t.Context(), application.Request{Interface: "wan", ProbeMode: "wired", ProbeURL: "http://typed.invalid/login?theme=pro", ProbeSchool: "chosen"})
|
|
want := []string{"http://typed.invalid/login?theme=pro", "http://school.invalid/full", "http://saved.invalid", "http://gateway.invalid"}
|
|
if len(candidates) != len(want) {
|
|
t.Fatal(candidates)
|
|
}
|
|
for i, c := range candidates {
|
|
if c.URL != want[i] {
|
|
t.Fatalf("%+v", candidates)
|
|
}
|
|
}
|
|
}
|