@@ -6,9 +6,11 @@ import (
66 "context"
77 "encoding/json"
88 "io"
9+ "net"
910 "net/http"
1011 "os"
1112 "os/exec"
13+ "path/filepath"
1214 "strconv"
1315 "strings"
1416 "testing"
@@ -26,12 +28,15 @@ func TestIntegration(t *testing.T) {
2628
2729 // Setup the httpbin upstream local server.
2830 httpbinHandler := httpbin .New ()
29- server := & http.Server {Addr : ":1234" , Handler : httpbinHandler ,
31+ server := & http.Server {Handler : httpbinHandler ,
3032 ReadHeaderTimeout : 5 * time .Second , IdleTimeout : 5 * time .Second ,
3133 WriteTimeout : 5 * time .Second ,
3234 }
35+ // Use tcp4 to avoid conflicting with any IPv6-only service already on :1234.
36+ httpbinListener , err := net .Listen ("tcp4" , ":1234" )
37+ require .NoError (t , err )
3338 go func () {
34- if err = server .ListenAndServe ( ); err != nil && err != http .ErrServerClosed {
39+ if err : = server .Serve ( httpbinListener ); err != nil && err != http .ErrServerClosed {
3540 t .Logf ("HTTP server error: %v" , err )
3641 }
3742 }()
@@ -43,7 +48,7 @@ func TestIntegration(t *testing.T) {
4348
4449 // Health check to ensure the server is up before starting tests.
4550 require .Eventually (t , func () bool {
46- resp , err := http .Get ("http://localhost :1234/uuid" )
51+ resp , err := http .Get ("http://127.0.0.1 :1234/uuid" )
4752 if err != nil {
4853 t .Logf ("httpbin server not ready yet: %v" , err )
4954 return false
@@ -60,6 +65,11 @@ func TestIntegration(t *testing.T) {
6065 require .NoError (t , os .Mkdir (accessLogsDir , 0o700 ))
6166 require .NoError (t , os .Chmod (accessLogsDir , 0o777 ))
6267
68+ // Detect the JVM server library directory so librust_module.so can dlopen
69+ // libjvm.so when the java_filter initialises the embedded JVM.
70+ jvmLibPath := jvmServerLibPath (t )
71+ t .Logf ("JVM lib path: %s" , jvmLibPath )
72+
6373 if envoyImage := cmp .Or (os .Getenv ("ENVOY_IMAGE" )); envoyImage != "" {
6474 cmd := exec .Command (
6575 "docker" ,
@@ -92,9 +102,15 @@ func TestIntegration(t *testing.T) {
92102
93103 cmd .Stdout = os .Stdout
94104 cmd .Stderr = os .Stderr
105+ existingLD := os .Getenv ("LD_LIBRARY_PATH" )
106+ ldLibPath := jvmLibPath
107+ if existingLD != "" {
108+ ldLibPath = jvmLibPath + ":" + existingLD
109+ }
95110 cmd .Env = append (os .Environ (),
96111 "ENVOY_DYNAMIC_MODULES_SEARCH_PATH=" + cwd ,
97112 "GODEBUG=cgocheck=0" ,
113+ "LD_LIBRARY_PATH=" + ldLibPath ,
98114 )
99115 require .NoError (t , cmd .Start ())
100116 defer func () {
@@ -422,6 +438,47 @@ func TestIntegration(t *testing.T) {
422438 }, 30 * time .Second , 200 * time .Millisecond )
423439 })
424440
441+ t .Run ("java_filter" , func (t * testing.T ) {
442+ require .Eventually (t , func () bool {
443+ req , err := http .NewRequest ("GET" , "http://127.0.0.1:1065/headers" , nil )
444+ require .NoError (t , err )
445+
446+ resp , err := http .DefaultClient .Do (req )
447+ if err != nil {
448+ t .Logf ("Envoy not ready yet: %v" , err )
449+ return false
450+ }
451+ defer func () {
452+ require .NoError (t , resp .Body .Close ())
453+ }()
454+ body , err := io .ReadAll (resp .Body )
455+ if err != nil {
456+ t .Logf ("Envoy not ready yet: %v" , err )
457+ return false
458+ }
459+
460+ t .Logf ("response: headers=%v, body=%s" , resp .Header , string (body ))
461+ require .Equal (t , 200 , resp .StatusCode )
462+
463+ // httpbin echoes request headers back as JSON.
464+ type httpBinHeadersBody struct {
465+ Headers map [string ][]string `json:"headers"`
466+ }
467+ var headersBody httpBinHeadersBody
468+ require .NoError (t , json .Unmarshal (body , & headersBody ))
469+
470+ // ExampleFilter adds x-java-filter: active to every request.
471+ require .Contains (t , headersBody .Headers ["X-Java-Filter" ], "active" ,
472+ "x-java-filter request header should be set by the Java filter" )
473+
474+ // ExampleFilter mirrors the :path back as x-java-filter-path on the response.
475+ require .Equal (t , "/headers" , resp .Header .Get ("x-java-filter-path" ),
476+ "x-java-filter-path response header should mirror the request :path" )
477+
478+ return true
479+ }, 30 * time .Second , 200 * time .Millisecond )
480+ })
481+
425482 t .Run ("http_metrics" , func (t * testing.T ) {
426483 // Send test request
427484 require .Eventually (t , func () bool {
@@ -495,3 +552,30 @@ func TestIntegration(t *testing.T) {
495552 }, 5 * time .Second , 200 * time .Millisecond )
496553 })
497554}
555+
556+ // jvmServerLibPath returns the directory containing libjvm.so, needed by the
557+ // java_filter at runtime so the Rust module can dlopen the JVM.
558+ // It first checks $JAVA_HOME, then falls back to running `java -XshowSettings:all -version`.
559+ func jvmServerLibPath (t * testing.T ) string {
560+ t .Helper ()
561+ javaHome := os .Getenv ("JAVA_HOME" )
562+ if javaHome == "" {
563+ out , err := exec .Command ("java" , "-XshowSettings:all" , "-version" ).CombinedOutput ()
564+ if err == nil {
565+ for _ , line := range strings .Split (string (out ), "\n " ) {
566+ if strings .Contains (line , "java.home" ) {
567+ parts := strings .SplitN (line , "=" , 2 )
568+ if len (parts ) == 2 {
569+ javaHome = strings .TrimSpace (parts [1 ])
570+ break
571+ }
572+ }
573+ }
574+ }
575+ }
576+ if javaHome == "" {
577+ t .Log ("JAVA_HOME not set and could not be detected; java_filter may fail to load libjvm.so" )
578+ return ""
579+ }
580+ return filepath .Join (javaHome , "lib" , "server" )
581+ }
0 commit comments