1+ /*
2+ * Licensed to the Apache Software Foundation (ASF) under one or more
3+ * contributor license agreements. See the NOTICE file distributed with
4+ * this work for additional information regarding copyright ownership.
5+ * The ASF licenses this file to you under the Apache License, Version 2.0
6+ * (the "License"); you may not use this file except in compliance with
7+ * the License. You may obtain a copy of the License at
8+ *
9+ * http://www.apache.org/licenses/LICENSE-2.0
10+ *
11+ * Unless required by applicable law or agreed to in writing, software
12+ * distributed under the License is distributed on an "AS IS" BASIS,
13+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+ * See the License for the specific language governing permissions and
15+ * limitations under the License.
16+ */
17+ package org .apache .logging .log4j .core .appender ;
18+
19+ import org .apache .logging .log4j .Level ;
20+ import org .apache .logging .log4j .core .Layout ;
21+ import org .apache .logging .log4j .core .config .Configuration ;
22+ import org .apache .logging .log4j .core .config .DefaultConfiguration ;
23+ import org .apache .logging .log4j .core .config .Property ;
24+ import org .apache .logging .log4j .core .net .ssl .SslConfiguration ;
25+ import org .apache .logging .log4j .core .layout .JsonLayout ;
26+ import org .apache .logging .log4j .status .StatusLogger ;
27+ import org .apache .logging .log4j .test .ListStatusListener ;
28+ import org .apache .logging .log4j .test .junit .UsingStatusListener ;
29+ import org .junit .jupiter .api .Test ;
30+ import org .mockito .Mockito ;
31+
32+ import java .net .MalformedURLException ;
33+ import java .net .URL ;
34+
35+ import static org .assertj .core .api .AssertionsForInterfaceTypes .assertThat ;
36+ import static org .junit .jupiter .api .Assertions .*;
37+ import static org .mockito .Mockito .*;
38+
39+ class HttpAppenderBuilderTest {
40+
41+ // Mock the LOGGER to verify error logs
42+ private final StatusLogger mockStatusLogger = Mockito .mock (StatusLogger .class );
43+
44+ private HttpAppender .Builder <?> getBuilder () {
45+ Configuration mockConfig = new DefaultConfiguration ();
46+ return HttpAppender .newBuilder ()
47+ .setConfiguration (mockConfig )
48+ .setName ("TestHttpAppender" ); // Name is required
49+ }
50+
51+ @ Test
52+ @ UsingStatusListener
53+ void testBuilderWithoutUrl (final ListStatusListener listener ) throws Exception {
54+ // Build the HttpAppender without URL
55+ HttpAppender appender = HttpAppender .newBuilder ()
56+ .setConfiguration (new DefaultConfiguration ())
57+ .setName ("TestAppender" )
58+ .setLayout (JsonLayout .createDefaultLayout ()) // Providing a layout here
59+ .build ();
60+
61+ // Verify that the error message for missing URL is captured
62+ assertThat (listener .findStatusData (Level .ERROR ))
63+ .anyMatch (statusData -> statusData .getMessage ().getFormattedMessage ().contains ("HttpAppender requires URL to be set." ));
64+ }
65+
66+ @ Test
67+ @ UsingStatusListener
68+ void testBuilderWithUrlAndWithoutLayout (final ListStatusListener listener ) throws Exception {
69+ // Build the HttpAppender with URL but without Layout
70+ HttpAppender appender = HttpAppender .newBuilder ()
71+ .setConfiguration (new DefaultConfiguration ())
72+ .setName ("TestAppender" )
73+ .setUrl (new URL ("http://localhost:8080/logs" )) // Providing the URL
74+ .build ();
75+
76+ // Verify that the error message for missing layout is captured
77+ assertThat (listener .findStatusData (Level .ERROR ))
78+ .anyMatch (statusData -> statusData .getMessage ().getFormattedMessage ().contains ("HttpAppender requires a layout to be set." ));
79+ }
80+
81+
82+ @ Test
83+ void testBuilderWithValidConfiguration () throws Exception {
84+ URL url = new URL ("http://example.com" );
85+ Layout <?> layout = JsonLayout .createDefaultLayout (); // Valid layout
86+
87+ HttpAppender .Builder <?> builder = getBuilder ()
88+ .setUrl (url )
89+ .setLayout (layout );
90+
91+ HttpAppender appender = builder .build ();
92+ assertNotNull (appender , "HttpAppender should be created with valid configuration." );
93+ }
94+
95+ @ Test
96+ void testBuilderWithCustomMethod () throws Exception {
97+ URL url = new URL ("http://example.com" );
98+ Layout <?> layout = JsonLayout .createDefaultLayout ();
99+ String customMethod = "PUT" ;
100+
101+ HttpAppender .Builder <?> builder = getBuilder ()
102+ .setUrl (url )
103+ .setLayout (layout )
104+ .setMethod (customMethod );
105+
106+ HttpAppender appender = builder .build ();
107+ assertNotNull (appender , "HttpAppender should be created with a custom HTTP method." );
108+ }
109+
110+ @ Test
111+ void testBuilderWithHeaders () throws Exception {
112+ URL url = new URL ("http://example.com" );
113+ Layout <?> layout = JsonLayout .createDefaultLayout ();
114+ Property [] headers = new Property []{
115+ Property .createProperty ("Header1" , "Value1" ),
116+ Property .createProperty ("Header2" , "Value2" )
117+ };
118+
119+ HttpAppender .Builder <?> builder = getBuilder ()
120+ .setUrl (url )
121+ .setLayout (layout )
122+ .setHeaders (headers );
123+
124+ HttpAppender appender = builder .build ();
125+ assertNotNull (appender , "HttpAppender should be created with headers." );
126+ }
127+
128+ @ Test
129+ void testBuilderWithSslConfiguration () throws Exception {
130+ URL url = new URL ("https://example.com" );
131+ Layout <?> layout = JsonLayout .createDefaultLayout ();
132+ SslConfiguration sslConfig = mock (SslConfiguration .class );
133+
134+ HttpAppender .Builder <?> builder = getBuilder ()
135+ .setUrl (url )
136+ .setLayout (layout )
137+ .setSslConfiguration (sslConfig );
138+
139+ HttpAppender appender = builder .build ();
140+ assertNotNull (appender , "HttpAppender should be created with SSL configuration." );
141+ }
142+
143+ @ Test
144+ void testBuilderWithInvalidUrl () {
145+ assertThrows (MalformedURLException .class , () -> new URL ("invalid-url" ));
146+ }
147+ }
0 commit comments