func TestMultiSitesRebuild(t *testing.T) { defer leaktest.Check(t)() testCommonResetState() siteConfig := testSiteConfig{DefaultContentLanguage: "fr"} sites := createMultiTestSites(t, siteConfig, multiSiteTOMLConfigTemplate) cfg := BuildCfg{Watching: true} err := sites.Build(cfg) if err != nil { t.Fatalf("Failed to build sites: %s", err) } _, err = hugofs.Destination().Open("public/en/sect/doc2/index.html") if err != nil { t.Fatalf("Unable to locate file") } enSite := sites.Sites[0] frSite := sites.Sites[1] assert.Len(t, enSite.Pages, 3) assert.Len(t, frSite.Pages, 3) // Verify translations docEn := readDestination(t, "public/en/sect/doc1-slug/index.html") assert.True(t, strings.Contains(docEn, "Hello"), "No Hello") docFr := readDestination(t, "public/fr/sect/doc1/index.html") assert.True(t, strings.Contains(docFr, "Bonjour"), "No Bonjour") // check single page content assertFileContent(t, "public/fr/sect/doc1/index.html", true, "Single", "Shortcode: Bonjour") assertFileContent(t, "public/en/sect/doc1-slug/index.html", true, "Single", "Shortcode: Hello") for i, this := range []struct { preFunc func(t *testing.T) events []fsnotify.Event assertFunc func(t *testing.T) }{ // * Remove doc // * Add docs existing languages // (Add doc new language: TODO(bep) we should load config.toml as part of these so we can add languages). // * Rename file // * Change doc // * Change a template // * Change language file { nil, []fsnotify.Event{{Name: "content/sect/doc2.en.md", Op: fsnotify.Remove}}, func(t *testing.T) { assert.Len(t, enSite.Pages, 2, "1 en removed") // Check build stats assert.Equal(t, 1, enSite.draftCount, "Draft") assert.Equal(t, 1, enSite.futureCount, "Future") assert.Equal(t, 1, enSite.expiredCount, "Expired") assert.Equal(t, 0, frSite.draftCount, "Draft") assert.Equal(t, 1, frSite.futureCount, "Future") assert.Equal(t, 1, frSite.expiredCount, "Expired") }, }, { func(t *testing.T) { writeNewContentFile(t, "new_en_1", "2016-07-31", "content/new1.en.md", -5) writeNewContentFile(t, "new_en_2", "1989-07-30", "content/new2.en.md", -10) writeNewContentFile(t, "new_fr_1", "2016-07-30", "content/new1.fr.md", 10) }, []fsnotify.Event{ {Name: "content/new1.en.md", Op: fsnotify.Create}, {Name: "content/new2.en.md", Op: fsnotify.Create}, {Name: "content/new1.fr.md", Op: fsnotify.Create}, }, func(t *testing.T) { assert.Len(t, enSite.Pages, 4) assert.Len(t, enSite.AllPages, 10) assert.Len(t, frSite.Pages, 4) assert.Equal(t, "new_fr_1", frSite.Pages[3].Title) assert.Equal(t, "new_en_2", enSite.Pages[0].Title) assert.Equal(t, "new_en_1", enSite.Pages[1].Title) rendered := readDestination(t, "public/en/new1/index.html") assert.True(t, strings.Contains(rendered, "new_en_1"), rendered) }, }, { func(t *testing.T) { p := "content/sect/doc1.en.md" doc1 := readSource(t, p) doc1 += "CHANGED" writeSource(t, p, doc1) }, []fsnotify.Event{{Name: "content/sect/doc1.en.md", Op: fsnotify.Write}}, func(t *testing.T) { assert.Len(t, enSite.Pages, 4) doc1 := readDestination(t, "public/en/sect/doc1-slug/index.html") assert.True(t, strings.Contains(doc1, "CHANGED"), doc1) }, }, // Rename a file { func(t *testing.T) { if err := hugofs.Source().Rename("content/new1.en.md", "content/new1renamed.en.md"); err != nil { t.Fatalf("Rename failed: %s", err) } }, []fsnotify.Event{ {Name: "content/new1renamed.en.md", Op: fsnotify.Rename}, {Name: "content/new1.en.md", Op: fsnotify.Rename}, }, func(t *testing.T) { assert.Len(t, enSite.Pages, 4, "Rename") assert.Equal(t, "new_en_1", enSite.Pages[1].Title) rendered := readDestination(t, "public/en/new1renamed/index.html") assert.True(t, strings.Contains(rendered, "new_en_1"), rendered) }}, { // Change a template func(t *testing.T) { template := "layouts/_default/single.html" templateContent := readSource(t, template) templateContent += "{{ print \"Template Changed\"}}" writeSource(t, template, templateContent) }, []fsnotify.Event{{Name: "layouts/_default/single.html", Op: fsnotify.Write}}, func(t *testing.T) { assert.Len(t, enSite.Pages, 4) assert.Len(t, enSite.AllPages, 10) assert.Len(t, frSite.Pages, 4) doc1 := readDestination(t, "public/en/sect/doc1-slug/index.html") assert.True(t, strings.Contains(doc1, "Template Changed"), doc1) }, }, { // Change a language file func(t *testing.T) { languageFile := "i18n/fr.yaml" langContent := readSource(t, languageFile) langContent = strings.Replace(langContent, "Bonjour", "Salut", 1) writeSource(t, languageFile, langContent) }, []fsnotify.Event{{Name: "i18n/fr.yaml", Op: fsnotify.Write}}, func(t *testing.T) { assert.Len(t, enSite.Pages, 4) assert.Len(t, enSite.AllPages, 10) assert.Len(t, frSite.Pages, 4) docEn := readDestination(t, "public/en/sect/doc1-slug/index.html") assert.True(t, strings.Contains(docEn, "Hello"), "No Hello") docFr := readDestination(t, "public/fr/sect/doc1/index.html") assert.True(t, strings.Contains(docFr, "Salut"), "No Salut") homeEn := enSite.getNode("home-0") require.NotNil(t, homeEn) require.Len(t, homeEn.Translations(), 3) require.Equal(t, "fr", homeEn.Translations()[0].Lang()) }, }, // Change a shortcode { func(t *testing.T) { writeSource(t, "layouts/shortcodes/shortcode.html", "Modified Shortcode: {{ i18n \"hello\" }}") }, []fsnotify.Event{ {Name: "layouts/shortcodes/shortcode.html", Op: fsnotify.Write}, }, func(t *testing.T) { assert.Len(t, enSite.Pages, 4) assert.Len(t, enSite.AllPages, 10) assert.Len(t, frSite.Pages, 4) assertFileContent(t, "public/fr/sect/doc1/index.html", true, "Single", "Modified Shortcode: Salut") assertFileContent(t, "public/en/sect/doc1-slug/index.html", true, "Single", "Modified Shortcode: Hello") }, }, } { if this.preFunc != nil { this.preFunc(t) } err = sites.Rebuild(cfg, this.events...) if err != nil { t.Fatalf("[%d] Failed to rebuild sites: %s", i, err) } this.assertFunc(t) } // Check that the drafts etc. are not built/processed/rendered. assertShouldNotBuild(t, sites) }
func doTestMultiSitesBuild(t *testing.T, configTemplate, configSuffix string) { defer leaktest.Check(t)() testCommonResetState() siteConfig := testSiteConfig{DefaultContentLanguage: "fr"} sites := createMultiTestSitesForConfig(t, siteConfig, configTemplate, configSuffix) err := sites.Build(BuildCfg{}) if err != nil { t.Fatalf("Failed to build sites: %s", err) } enSite := sites.Sites[0] assert.Equal(t, "en", enSite.Language.Lang) if len(enSite.Pages) != 3 { t.Fatal("Expected 3 english pages") } assert.Len(t, enSite.Source.Files(), 13, "should have 13 source files") assert.Len(t, enSite.AllPages, 8, "should have 8 total pages (including translations)") doc1en := enSite.Pages[0] permalink, err := doc1en.Permalink() assert.NoError(t, err, "permalink call failed") assert.Equal(t, "http://example.com/blog/en/sect/doc1-slug/", permalink, "invalid doc1.en permalink") assert.Len(t, doc1en.Translations(), 1, "doc1-en should have one translation, excluding itself") doc2 := enSite.Pages[1] permalink, err = doc2.Permalink() assert.NoError(t, err, "permalink call failed") assert.Equal(t, "http://example.com/blog/en/sect/doc2/", permalink, "invalid doc2 permalink") doc3 := enSite.Pages[2] permalink, err = doc3.Permalink() assert.NoError(t, err, "permalink call failed") // Note that /superbob is a custom URL set in frontmatter. // We respect that URL literally (it can be /search.json) // and do no not do any language code prefixing. assert.Equal(t, "http://example.com/blog/superbob", permalink, "invalid doc3 permalink") assert.Equal(t, "/superbob", doc3.URL(), "invalid url, was specified on doc3") assertFileContent(t, "public/superbob/index.html", true, "doc3|Hello|en") assert.Equal(t, doc2.Next, doc3, "doc3 should follow doc2, in .Next") doc1fr := doc1en.Translations()[0] permalink, err = doc1fr.Permalink() assert.NoError(t, err, "permalink call failed") assert.Equal(t, "http://example.com/blog/fr/sect/doc1/", permalink, "invalid doc1fr permalink") assert.Equal(t, doc1en.Translations()[0], doc1fr, "doc1-en should have doc1-fr as translation") assert.Equal(t, doc1fr.Translations()[0], doc1en, "doc1-fr should have doc1-en as translation") assert.Equal(t, "fr", doc1fr.Language().Lang) doc4 := enSite.AllPages[4] permalink, err = doc4.Permalink() assert.NoError(t, err, "permalink call failed") assert.Equal(t, "http://example.com/blog/fr/sect/doc4/", permalink, "invalid doc4 permalink") assert.Equal(t, "/blog/fr/sect/doc4/", doc4.URL()) assert.Len(t, doc4.Translations(), 0, "found translations for doc4") doc5 := enSite.AllPages[5] permalink, err = doc5.Permalink() assert.NoError(t, err, "permalink call failed") assert.Equal(t, "http://example.com/blog/fr/somewhere/else/doc5", permalink, "invalid doc5 permalink") // Taxonomies and their URLs assert.Len(t, enSite.Taxonomies, 1, "should have 1 taxonomy") tags := enSite.Taxonomies["tags"] assert.Len(t, tags, 2, "should have 2 different tags") assert.Equal(t, tags["tag1"][0].Page, doc1en, "first tag1 page should be doc1") frSite := sites.Sites[1] assert.Equal(t, "fr", frSite.Language.Lang) assert.Len(t, frSite.Pages, 3, "should have 3 pages") assert.Len(t, frSite.AllPages, 8, "should have 8 total pages (including translations)") for _, frenchPage := range frSite.Pages { assert.Equal(t, "fr", frenchPage.Lang()) } // Check redirect to main language, French languageRedirect := readDestination(t, "public/index.html") require.True(t, strings.Contains(languageRedirect, "0; url=http://example.com/blog/fr"), languageRedirect) // check home page content (including data files rendering) assertFileContent(t, "public/en/index.html", true, "Home Page 1", "Hello", "Hugo Rocks!") assertFileContent(t, "public/fr/index.html", true, "Home Page 1", "Bonjour", "Hugo Rocks!") // check single page content assertFileContent(t, "public/fr/sect/doc1/index.html", true, "Single", "Shortcode: Bonjour") assertFileContent(t, "public/en/sect/doc1-slug/index.html", true, "Single", "Shortcode: Hello") // Check node translations homeEn := enSite.getNode("home-0") require.NotNil(t, homeEn) require.Len(t, homeEn.Translations(), 3) require.Equal(t, "fr", homeEn.Translations()[0].Lang()) require.Equal(t, "nn", homeEn.Translations()[1].Lang()) require.Equal(t, "På nynorsk", homeEn.Translations()[1].Title) require.Equal(t, "nb", homeEn.Translations()[2].Lang()) require.Equal(t, "På bokmål", homeEn.Translations()[2].Title, configSuffix) require.Equal(t, "Bokmål", homeEn.Translations()[2].Language().LanguageName, configSuffix) sectFr := frSite.getNode("sect-sect-0") require.NotNil(t, sectFr) require.Equal(t, "fr", sectFr.Lang()) require.Len(t, sectFr.Translations(), 1) require.Equal(t, "en", sectFr.Translations()[0].Lang()) require.Equal(t, "Sects", sectFr.Translations()[0].Title) nnSite := sites.Sites[2] require.Equal(t, "nn", nnSite.Language.Lang) taxNn := nnSite.getNode("taxlist-lag-0") require.NotNil(t, taxNn) require.Len(t, taxNn.Translations(), 1) require.Equal(t, "nb", taxNn.Translations()[0].Lang()) taxTermNn := nnSite.getNode("tax-lag-sogndal-0") require.NotNil(t, taxTermNn) require.Len(t, taxTermNn.Translations(), 1) require.Equal(t, "nb", taxTermNn.Translations()[0].Lang()) // Check sitemap(s) sitemapIndex := readDestination(t, "public/sitemap.xml") require.True(t, strings.Contains(sitemapIndex, "<loc>http://example.com/blog/en/sitemap.xml</loc>"), sitemapIndex) require.True(t, strings.Contains(sitemapIndex, "<loc>http://example.com/blog/fr/sitemap.xml</loc>"), sitemapIndex) sitemapEn := readDestination(t, "public/en/sitemap.xml") sitemapFr := readDestination(t, "public/fr/sitemap.xml") require.True(t, strings.Contains(sitemapEn, "http://example.com/blog/en/sect/doc2/"), sitemapEn) require.True(t, strings.Contains(sitemapFr, "http://example.com/blog/fr/sect/doc1/"), sitemapFr) // Check taxonomies enTags := enSite.Taxonomies["tags"] frTags := frSite.Taxonomies["plaques"] require.Len(t, enTags, 2, fmt.Sprintf("Tags in en: %v", enTags)) require.Len(t, frTags, 2, fmt.Sprintf("Tags in fr: %v", frTags)) require.NotNil(t, enTags["tag1"]) require.NotNil(t, frTags["frtag1"]) readDestination(t, "public/fr/plaques/frtag1/index.html") readDestination(t, "public/en/tags/tag1/index.html") // Check Blackfriday config assert.True(t, strings.Contains(string(doc1fr.Content), "«"), string(doc1fr.Content)) assert.False(t, strings.Contains(string(doc1en.Content), "«"), string(doc1en.Content)) assert.True(t, strings.Contains(string(doc1en.Content), "“"), string(doc1en.Content)) // Check that the drafts etc. are not built/processed/rendered. assertShouldNotBuild(t, sites) // en and nn have custom site menus require.Len(t, frSite.Menus, 0, "fr: "+configSuffix) require.Len(t, enSite.Menus, 1, "en: "+configSuffix) require.Len(t, nnSite.Menus, 1, "nn: "+configSuffix) require.Equal(t, "Home", enSite.Menus["main"].ByName()[0].Name) require.Equal(t, "Heim", nnSite.Menus["main"].ByName()[0].Name) }