| 1 | package pmi |
| 2 | |
| 3 | import ( |
| 4 | "context" |
| 5 | "io" |
| 6 | "net/http" |
| 7 | "strings" |
| 8 | "testing" |
| 9 | "time" |
| 10 | ) |
| 11 | |
| 12 | type roundTripFunc func(*http.Request) (*http.Response, error) |
| 13 | |
| 14 | func (f roundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) { |
| 15 | return f(req) |
| 16 | } |
| 17 | |
| 18 | func newTestHTTPClient(fn roundTripFunc) *http.Client { |
| 19 | return &http.Client{Transport: fn} |
| 20 | } |
| 21 | |
| 22 | func TestClientFetchSuccess(t *testing.T) { |
| 23 | sampleXML := `<?xml version="1.0" encoding="UTF-8"?> |
| 24 | <PerformanceMonitor responseStatus="ok" version="8.5.5"> |
| 25 | <Node name="Node01"> |
| 26 | <Server name="server1"> |
| 27 | <Stat name="JVM"> |
| 28 | <CountStatistic name="Requests" count="10" unit="count"/> |
| 29 | <Stat name="Nested"> |
| 30 | <TimeStatistic name="Response" count="2" totalTime="100" unit="ms"/> |
| 31 | </Stat> |
| 32 | </Stat> |
| 33 | </Server> |
| 34 | </Node> |
| 35 | <Stat name="libertyRoot"> |
| 36 | <DoubleStatistic name="cpu" double="0.5" unit="percent"/> |
| 37 | </Stat> |
| 38 | </PerformanceMonitor>` |
| 39 | |
| 40 | var capturedQuery string |
| 41 | httpClient := newTestHTTPClient(func(r *http.Request) (*http.Response, error) { |
| 42 | capturedQuery = r.URL.RawQuery |
| 43 | return &http.Response{ |
| 44 | StatusCode: http.StatusOK, |
| 45 | Body: io.NopCloser(strings.NewReader(sampleXML)), |
| 46 | Header: make(http.Header), |
| 47 | }, nil |
| 48 | }) |
| 49 | |
| 50 | client, err := NewClientWithHTTP(Config{URL: "https://example.com/wasPerfTool/servlet/perfservlet", StatsType: "extended"}, httpClient) |
| 51 | if err != nil { |
| 52 | t.Fatalf("NewClientWithHTTP failed: %v", err) |
| 53 | } |
| 54 | |
| 55 | ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) |
| 56 | defer cancel() |
| 57 | |
| 58 | snapshot, err := client.Fetch(ctx) |
| 59 | if err != nil { |
| 60 | t.Fatalf("Fetch failed: %v", err) |
| 61 | } |
| 62 | |
| 63 | if capturedQuery != "stats=extended" { |
| 64 | t.Fatalf("expected stats query to enforce level, got %q", capturedQuery) |
| 65 | } |
| 66 | |
| 67 | if snapshot.ResponseStatus != "ok" { |
| 68 | t.Fatalf("unexpected response status: %s", snapshot.ResponseStatus) |
| 69 | } |
| 70 | if snapshot.Version != "8.5.5" { |
| 71 | t.Fatalf("unexpected version: %s", snapshot.Version) |
| 72 | } |
| 73 | |
| 74 | if len(snapshot.Nodes) != 1 { |
| 75 | t.Fatalf("expected one node, got %d", len(snapshot.Nodes)) |
| 76 | } |
| 77 | |
| 78 | stat := snapshot.Nodes[0].Servers[0].Stats[0] |
| 79 | if stat.Path != "Node01/server1/JVM" { |
| 80 | t.Fatalf("unexpected stat path: %s", stat.Path) |
| 81 | } |
| 82 | if stat.CountStatistic == nil || stat.CountStatistic.Name != "Requests" { |
| 83 | t.Fatalf("count statistic not normalised") |
| 84 | } |
| 85 | |
| 86 | nested := stat.SubStats[0] |
| 87 | if nested.Path != "Node01/server1/JVM/Nested" { |
| 88 | t.Fatalf("unexpected nested stat path: %s", nested.Path) |
| 89 | } |
| 90 | if nested.TimeStatistic == nil || nested.TimeStatistic.Name != "Response" { |
| 91 | t.Fatalf("time statistic not normalised") |
| 92 | } |
| 93 | |
| 94 | rootStat := snapshot.Stats[0] |
| 95 | if rootStat.Path != "libertyRoot" { |
| 96 | t.Fatalf("unexpected root stat path: %s", rootStat.Path) |
| 97 | } |
| 98 | if rootStat.DoubleStatistic == nil || rootStat.DoubleStatistic.Name != "cpu" { |
| 99 | t.Fatalf("double statistic not normalised") |
| 100 | } |
| 101 | } |
| 102 | |
| 103 | func TestClientFetchHTTPError(t *testing.T) { |
| 104 | httpClient := newTestHTTPClient(func(r *http.Request) (*http.Response, error) { |
| 105 | return &http.Response{ |
| 106 | StatusCode: http.StatusInternalServerError, |
| 107 | Body: io.NopCloser(strings.NewReader("boom")), |
| 108 | }, nil |
| 109 | }) |
| 110 | |
| 111 | client, err := NewClientWithHTTP(Config{URL: "https://example.com/wasPerfTool/servlet/perfservlet"}, httpClient) |
| 112 | if err != nil { |
| 113 | t.Fatalf("NewClientWithHTTP failed: %v", err) |
| 114 | } |
| 115 | |
| 116 | ctx, cancel := context.WithTimeout(context.Background(), time.Second) |
| 117 | defer cancel() |
| 118 | |
| 119 | if _, err := client.Fetch(ctx); err == nil { |
| 120 | t.Fatalf("expected fetch error for 500 response") |
| 121 | } |
| 122 | } |
| 123 | |
| 124 | func TestClientFetchContextCancellation(t *testing.T) { |
| 125 | httpClient := newTestHTTPClient(func(r *http.Request) (*http.Response, error) { |
| 126 | <-r.Context().Done() |
| 127 | return nil, r.Context().Err() |
| 128 | }) |
| 129 | |
| 130 | client, err := NewClientWithHTTP(Config{URL: "https://example.com/wasPerfTool/servlet/perfservlet"}, httpClient) |
| 131 | if err != nil { |
| 132 | t.Fatalf("NewClientWithHTTP failed: %v", err) |
| 133 | } |
| 134 | |
| 135 | ctx, cancel := context.WithCancel(context.Background()) |
| 136 | cancel() |
| 137 | |
| 138 | if _, err := client.Fetch(ctx); err == nil { |
| 139 | t.Fatalf("expected fetch cancellation error") |
| 140 | } |
| 141 | } |