server_test.go (7335B)
1 // Copyright 2015 The Hugo Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package commands 15 16 import ( 17 "fmt" 18 "net/http" 19 "os" 20 "path/filepath" 21 "runtime" 22 "strings" 23 "testing" 24 "time" 25 26 "github.com/gohugoio/hugo/config" 27 "github.com/gohugoio/hugo/helpers" 28 "golang.org/x/net/context" 29 "golang.org/x/sync/errgroup" 30 31 qt "github.com/frankban/quicktest" 32 ) 33 34 // Issue 9518 35 func TestServerPanicOnConfigError(t *testing.T) { 36 c := qt.New(t) 37 38 config := ` 39 [markup] 40 [markup.highlight] 41 linenos='table' 42 ` 43 44 r := runServerTest(c, 0, config) 45 46 c.Assert(r.err, qt.IsNotNil) 47 c.Assert(r.err.Error(), qt.Contains, "cannot parse 'Highlight.LineNos' as bool:") 48 } 49 50 func TestServerFlags(t *testing.T) { 51 c := qt.New(t) 52 53 assertPublic := func(c *qt.C, r serverTestResult, renderStaticToDisk bool) { 54 c.Assert(r.err, qt.IsNil) 55 c.Assert(r.homesContent[0], qt.Contains, "Environment: development") 56 c.Assert(r.publicDirnames["myfile.txt"], qt.Equals, renderStaticToDisk) 57 58 } 59 60 for _, test := range []struct { 61 flag string 62 assert func(c *qt.C, r serverTestResult) 63 }{ 64 {"", func(c *qt.C, r serverTestResult) { 65 assertPublic(c, r, false) 66 }}, 67 {"--renderToDisk", func(c *qt.C, r serverTestResult) { 68 assertPublic(c, r, true) 69 }}, 70 {"--renderStaticToDisk", func(c *qt.C, r serverTestResult) { 71 assertPublic(c, r, true) 72 }}, 73 } { 74 c.Run(test.flag, func(c *qt.C) { 75 config := ` 76 baseURL="https://example.org" 77 ` 78 79 var args []string 80 if test.flag != "" { 81 args = strings.Split(test.flag, "=") 82 } 83 84 r := runServerTest(c, 1, config, args...) 85 86 test.assert(c, r) 87 88 }) 89 90 } 91 92 } 93 94 func TestServerBugs(t *testing.T) { 95 c := qt.New(t) 96 97 for _, test := range []struct { 98 name string 99 config string 100 flag string 101 numservers int 102 assert func(c *qt.C, r serverTestResult) 103 }{ 104 // Issue 9788 105 {"PostProcess, memory", "", "", 1, func(c *qt.C, r serverTestResult) { 106 c.Assert(r.err, qt.IsNil) 107 c.Assert(r.homesContent[0], qt.Contains, "PostProcess: /foo.min.css") 108 }}, 109 {"PostProcess, disk", "", "--renderToDisk", 1, func(c *qt.C, r serverTestResult) { 110 c.Assert(r.err, qt.IsNil) 111 c.Assert(r.homesContent[0], qt.Contains, "PostProcess: /foo.min.css") 112 }}, 113 // Isue 9901 114 {"Multihost", ` 115 defaultContentLanguage = 'en' 116 [languages] 117 [languages.en] 118 baseURL = 'https://example.com' 119 title = 'My blog' 120 weight = 1 121 [languages.fr] 122 baseURL = 'https://example.fr' 123 title = 'Mon blogue' 124 weight = 2 125 `, "", 2, func(c *qt.C, r serverTestResult) { 126 c.Assert(r.err, qt.IsNil) 127 for i, s := range []string{"My blog", "Mon blogue"} { 128 c.Assert(r.homesContent[i], qt.Contains, s) 129 } 130 }}, 131 } { 132 c.Run(test.name, func(c *qt.C) { 133 if test.config == "" { 134 test.config = ` 135 baseURL="https://example.org" 136 ` 137 } 138 139 var args []string 140 if test.flag != "" { 141 args = strings.Split(test.flag, "=") 142 } 143 r := runServerTest(c, test.numservers, test.config, args...) 144 test.assert(c, r) 145 146 }) 147 148 } 149 150 } 151 152 type serverTestResult struct { 153 err error 154 homesContent []string 155 publicDirnames map[string]bool 156 } 157 158 func runServerTest(c *qt.C, getNumHomes int, config string, args ...string) (result serverTestResult) { 159 dir := createSimpleTestSite(c, testSiteConfig{configTOML: config}) 160 161 sp, err := helpers.FindAvailablePort() 162 c.Assert(err, qt.IsNil) 163 port := sp.Port 164 165 defer func() { 166 os.RemoveAll(dir) 167 }() 168 169 stop := make(chan bool) 170 171 b := newCommandsBuilder() 172 scmd := b.newServerCmdSignaled(stop) 173 174 cmd := scmd.getCommand() 175 args = append([]string{"-s=" + dir, fmt.Sprintf("-p=%d", port)}, args...) 176 cmd.SetArgs(args) 177 178 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 179 defer cancel() 180 wg, ctx := errgroup.WithContext(ctx) 181 182 wg.Go(func() error { 183 _, err := cmd.ExecuteC() 184 return err 185 }) 186 187 if getNumHomes > 0 { 188 // Esp. on slow CI machines, we need to wait a little before the web 189 // server is ready. 190 time.Sleep(567 * time.Millisecond) 191 result.homesContent = make([]string, getNumHomes) 192 for i := 0; i < getNumHomes; i++ { 193 func() { 194 resp, err := http.Get(fmt.Sprintf("http://localhost:%d/", port+i)) 195 c.Check(err, qt.IsNil) 196 c.Check(resp.StatusCode, qt.Equals, http.StatusOK) 197 if err == nil { 198 defer resp.Body.Close() 199 result.homesContent[i] = helpers.ReaderToString(resp.Body) 200 } 201 }() 202 } 203 } 204 205 time.Sleep(1 * time.Second) 206 207 select { 208 case <-stop: 209 case stop <- true: 210 } 211 212 pubFiles, err := os.ReadDir(filepath.Join(dir, "public")) 213 c.Check(err, qt.IsNil) 214 result.publicDirnames = make(map[string]bool) 215 for _, f := range pubFiles { 216 result.publicDirnames[f.Name()] = true 217 } 218 219 result.err = wg.Wait() 220 221 return 222 223 } 224 225 func TestFixURL(t *testing.T) { 226 type data struct { 227 TestName string 228 CLIBaseURL string 229 CfgBaseURL string 230 AppendPort bool 231 Port int 232 Result string 233 } 234 tests := []data{ 235 {"Basic http localhost", "", "http://foo.com", true, 1313, "http://localhost:1313/"}, 236 {"Basic https production, http localhost", "", "https://foo.com", true, 1313, "http://localhost:1313/"}, 237 {"Basic subdir", "", "http://foo.com/bar", true, 1313, "http://localhost:1313/bar/"}, 238 {"Basic production", "http://foo.com", "http://foo.com", false, 80, "http://foo.com/"}, 239 {"Production subdir", "http://foo.com/bar", "http://foo.com/bar", false, 80, "http://foo.com/bar/"}, 240 {"No http", "", "foo.com", true, 1313, "//localhost:1313/"}, 241 {"Override configured port", "", "foo.com:2020", true, 1313, "//localhost:1313/"}, 242 {"No http production", "foo.com", "foo.com", false, 80, "//foo.com/"}, 243 {"No http production with port", "foo.com", "foo.com", true, 2020, "//foo.com:2020/"}, 244 {"No config", "", "", true, 1313, "//localhost:1313/"}, 245 } 246 247 for _, test := range tests { 248 t.Run(test.TestName, func(t *testing.T) { 249 b := newCommandsBuilder() 250 s := b.newServerCmd() 251 v := config.NewWithTestDefaults() 252 baseURL := test.CLIBaseURL 253 v.Set("baseURL", test.CfgBaseURL) 254 s.serverAppend = test.AppendPort 255 s.serverPort = test.Port 256 result, err := s.fixURL(v, baseURL, s.serverPort) 257 if err != nil { 258 t.Errorf("Unexpected error %s", err) 259 } 260 if result != test.Result { 261 t.Errorf("Expected %q, got %q", test.Result, result) 262 } 263 }) 264 } 265 } 266 267 func TestRemoveErrorPrefixFromLog(t *testing.T) { 268 c := qt.New(t) 269 content := `ERROR 2018/10/07 13:11:12 Error while rendering "home": template: _default/baseof.html:4:3: executing "main" at <partial "logo" .>: error calling partial: template: partials/logo.html:5:84: executing "partials/logo.html" at <$resized.AHeight>: can't evaluate field AHeight in type *resource.Image 270 ERROR 2018/10/07 13:11:12 Rebuild failed: logged 1 error(s) 271 ` 272 273 withoutError := removeErrorPrefixFromLog(content) 274 275 c.Assert(strings.Contains(withoutError, "ERROR"), qt.Equals, false) 276 } 277 278 func isWindowsCI() bool { 279 return runtime.GOOS == "windows" && os.Getenv("CI") != "" 280 }