2015-11-10 18 views
10

Sto provando a eseguire il test dell'unità una risorsa evento server inoltrato con un cookie aggiuntivo. Sto già usando Jersey per EventSource e JavaX per il client. Il seguente codice funziona correttamente:Client di eventi inviati server con cookie aggiuntivo

WebTarget target = ClientBuilder.newBuilder() 
     .register(SseFeature.class) 
     .build() 
     .target("http://localhost:8080/sse"); 
    EventSource eventSource = EventSource.target(target).build(); 
    EventListener listener = new EventListener() { 
     @Override 
     public void onEvent(InboundEvent inboundEvent) { 
      LOG.info(inboundEvent.readData(String.class)); 
     } 
    }; 
    eventSource.register(listener); 
    eventSource.open(); 
    serverEventManager.send("/sse", "foo"); 
    eventSource.close(); 

Hoewever, per un test di unità aggiuntivo, è necessario aggiungere un cookie aggiuntivo alla richiesta. Ho già tryed seguente

target.(...).request.cookie("foo", "bar"); 

Ma questo restituisce un costruttore da cui non riesco a creare il WebTarget richiesto per l'EventSource.

risposta

8

Ecco cosa c'è accade all'interno EventSource di stabilire in contatto alla data WebTarget:

 private Invocation.Builder prepareHandshakeRequest() { 
      Invocation.Builder request = EventSource.this.target 
        .request(new MediaType[] { SseFeature.SERVER_SENT_EVENTS_TYPE }); 
      if ((this.lastEventId != null) && (!(this.lastEventId.isEmpty()))) { 
       request.header("Last-Event-ID", this.lastEventId); 
      } 
      if (EventSource.this.disableKeepAlive) { 
       request.header("Connection", "close"); 
      } 
      return request; 
      } 

Come possiamo vedere - nessuna possibilità di aggiungere un cookie qui.

Quindi WebTarget.request(new MediaType[] { SseFeature.SERVER_SENT_EVENTS_TYPE }) deve restituire un Generatore che ha aggiunto il cookie desiderato a .

Considerate questa classe delegante aggiungendo il cookie desiderato a tutti i metodi request* Tipo:

public class CookieAddedWebTarget implements WebTarget { 

    private WebTarget base; 

    private Cookie cookie; 

    public CookieAddedWebTarget(WebTarget base, Cookie cookie) { 
     this.base = base; 
     this.cookie = cookie; 
    } 

    // Inject that cookie whenever someone requests a Builder (like EventSource does): 
    public Builder request() { 
     return base.request().cookie(cookie); 
    } 

    public Builder request(String... paramArrayOfString) { 
     return base.request(paramArrayOfString).cookie(cookie); 
    } 

    public Builder request(MediaType... paramArrayOfMediaType) { 
     return base.request(paramArrayOfMediaType).cookie(cookie); 
    } 

    public Configuration getConfiguration() { 
     return base.getConfiguration(); 
    } 

    //All other methods from WebTarget are delegated as-is: 

    public URI getUri() { 
     return base.getUri(); 
    } 

    public UriBuilder getUriBuilder() { 
     return base.getUriBuilder(); 
    } 

    public WebTarget path(String paramString) { 
     return base.path(paramString); 
    } 

    public WebTarget matrixParam(String paramString, Object... paramArrayOfObject) { 
     return base.matrixParam(paramString, paramArrayOfObject); 
    } 

    public WebTarget property(String paramString, Object paramObject) { 
     return base.property(paramString, paramObject); 
    } 

    public WebTarget queryParam(String paramString, Object... paramArrayOfObject) { 
     return base.queryParam(paramString, paramArrayOfObject); 
    } 

    public WebTarget register(Class<?> paramClass, Class<?>... paramArrayOfClass) { 
     return base.register(paramClass, paramArrayOfClass); 
    } 

    public WebTarget register(Class<?> paramClass, int paramInt) { 
     return base.register(paramClass, paramInt); 
    } 

    public WebTarget register(Class<?> paramClass, Map<Class<?>, Integer> paramMap) { 
     return base.register(paramClass, paramMap); 
    } 

    public WebTarget register(Class<?> paramClass) { 
     return base.register(paramClass); 
    } 

    public WebTarget register(Object paramObject, Class<?>... paramArrayOfClass) { 
     return base.register(paramObject, paramArrayOfClass); 
    } 

    public WebTarget register(Object paramObject, int paramInt) { 
     return base.register(paramObject, paramInt); 
    } 

    public WebTarget register(Object paramObject, Map<Class<?>, Integer> paramMap) { 
     return base.register(paramObject, paramMap); 
    } 

    public WebTarget register(Object paramObject) { 
     return base.register(paramObject); 
    } 

    public WebTarget resolveTemplate(String paramString, Object paramObject) { 
     return base.resolveTemplate(paramString, paramObject); 
    } 

    public WebTarget resolveTemplate(String paramString, Object paramObject, boolean paramBoolean) { 
     return base.resolveTemplate(paramString, paramObject, paramBoolean); 
    } 

    public WebTarget resolveTemplateFromEncoded(String paramString, Object paramObject) { 
     return base.resolveTemplateFromEncoded(paramString, paramObject); 
    } 

    public WebTarget resolveTemplates(Map<String, Object> paramMap) { 
     return base.resolveTemplates(paramMap); 
    } 

    public WebTarget resolveTemplates(Map<String, Object> paramMap, boolean paramBoolean) { 
     return base.resolveTemplates(paramMap, paramBoolean); 
    } 

    public WebTarget resolveTemplatesFromEncoded(Map<String, Object> paramMap) { 
     return base.resolveTemplatesFromEncoded(paramMap); 
    } 

} 

Ora si dovrebbe essere in grado di reerite il test a:

EventSource eventSource = EventSource.target(new CookieAddedWebTarget(target, 
          new Cookie("name", "value"))).build(); 

e dovrebbe essere inserito il cookie.

Avvertenza: non ho modo di testarlo. Soluzione basata solo sulla lettura del codice sorgente di jersey-media-sse-2.22.1.

Buona fortuna.

+0

Ho appena aggiornato il mio test case e funziona. Grazie! – svenkubiak

+0

Sì, funziona. Ma seriamente, la gente della maglia potrebbe rendere questo un po 'più conveniente, no? – Hank

3

È possibile impostare il cookie in un ClientRequestFilter. Anche se lo getCookies() su ClientRequestContext è immutabile, dovresti ricordare che un cookie non è tecnicamente altro che un'intestazione. E la mappa delle intestazioni nel contesto della richiesta è mutabile. Così si potrebbe fare qualcosa di simile

public static class SseCookieFilter implements ClientRequestFilter { 

    @Override 
    public void filter(ClientRequestContext requestContext) throws IOException { 
     Cookie cookie = new Cookie("foo", "bar"); 
     requestContext.getHeaders().add("Cookie", cookie.toString()); 
    } 
} 

Basta registrarsi il filtro con il cliente (client.register(new SseCookieFilter())). Sarebbe lo stesso risultato come se si dovesse fare

target.(...).request().cookie("foo", "bar"); 

Ecco un esempio completo utilizzando Jersey Test Framework

public class SseCookieFilterTest extends JerseyTest { 

    @Path("events") 
    public static class SseResource { 

     @GET 
     @Produces(SseFeature.SERVER_SENT_EVENTS) 
     public EventOutput getServerSentEvents(@CookieParam("foo") String foo) { 
      final EventOutput eventOutput = new EventOutput(); 
      new Thread(() -> { 
       try { 
        final OutboundEvent.Builder eventBuilder 
          = new OutboundEvent.Builder(); 
        eventBuilder.name("message"); 
        eventBuilder.data(String.class, "Blah " + foo + "!!!"); 
        final OutboundEvent event = eventBuilder.build(); 
        eventOutput.write(event); 

       } catch (IOException e) { 
        throw new RuntimeException(e); 
       } finally { 
        try { 
         eventOutput.close(); 
        } catch (IOException ioClose) { 
         throw new RuntimeException(ioClose); 
        } 
       } 
      }).start(); 
      return eventOutput; 
     } 
    } 

    public static class SseCookieFilter implements ClientRequestFilter { 

     @Override 
     public void filter(ClientRequestContext requestContext) throws IOException { 
      Cookie cookie = new Cookie("foo", "bar"); 
      requestContext.getHeaders().add("Cookie", cookie.toString()); 
     } 
    } 

    @Override 
    public ResourceConfig configure() { 
     return new ResourceConfig(SseResource.class) 
       .register(new LoggingFilter()); 
    } 

    @Test 
    public void doit() throws Exception { 
     Client client = ClientBuilder.newBuilder() 
       .register(SseFeature.class).build(); 
     client.register(new SseCookieFilter()); 
     WebTarget target = client.target("http://localhost:9998/events"); 
     EventSource eventSource = EventSource.target(target).build(); 
     EventListener listener = (InboundEvent inboundEvent) -> { 
      System.out.println("From server ---====++++> " 
        + inboundEvent.readData(String.class)); 
     }; 
     eventSource.register(listener, "message"); 
     eventSource.open(); 
     Thread.sleep(100); 
     eventSource.close(); 
    } 
} 

Queste sono le uniche dipendenze necessarie per testare

<dependency> 
    <groupId>org.glassfish.jersey.test-framework.providers</groupId> 
    <artifactId>jersey-test-framework-provider-grizzly2</artifactId> 
    <version>${jersey2.version}</version> 
    <scope>test</scope> 
</dependency> 
<dependency> 
    <groupId>org.glassfish.jersey.media</groupId> 
    <artifactId>jersey-media-sse</artifactId> 
    <version>${jersey2.version}</version> 
    <scope>test</scope> 
</dependency> 

Ecco il lato server risulta dal LoggingFilter Mi sono registrato sul server nel test

INFO: 1 * Server has received a request on thread grizzly-http-server-2 
1 > GET http://localhost:9998/events 
1 > accept: text/event-stream 
1 > connection: close 
1 > cookie: $Version=1;foo=bar 
1 > host: localhost:9998 
1 > user-agent: Jersey/2.19 (HttpUrlConnection 1.8.0_31) 

INFO: 1 * Server responded with a response on thread grizzly-http-server-2 
1 < 200 
1 < Content-Type: text/event-stream 

From server ---====++++> Blah bar!!!