Exemple #1
0
// ログインして /@:account_name のページにアクセスして一番上の投稿にコメントする
// 簡略化のために画像や静的ファイルへのアクセスはスキップする
func commentScenario(s *checker.Session, me user, accountName string, sentence string) {
	var csrfToken string
	var postID string
	var ok bool

	login := checker.NewAction("POST", "/login")
	login.ExpectedLocation = `^/$`
	login.Description = "ログインできること"
	login.PostData = map[string]string{
		"account_name": me.AccountName,
		"password":     me.Password,
	}
	err := login.Play(s)
	if err != nil {
		return
	}

	userPage := checker.NewAction("GET", "/@"+accountName)
	userPage.Description = "ユーザーページが表示できること"
	userPage.CheckFunc = checkHTML(func(doc *goquery.Document) error {

		sel := doc.Find(`div.isu-post`).First()

		if sel.Length() == 0 {
			return nil // 1枚も投稿が無いユーザー
		}

		csrfToken, ok = sel.Find(`input[name="csrf_token"]`).First().Attr("value")
		if !ok {
			return errors.New("CSRFトークンが取得できません")
		}

		postID, ok = sel.Find(`input[name="post_id"]`).First().Attr("value")
		if !ok {
			return errors.New("post_idが取得できません")
		}

		return nil
	})
	err = userPage.Play(s)
	if err != nil {
		return
	}

	if postID == "" {
		return
	}

	comment := checker.NewAction("POST", "/comment")
	comment.ExpectedLocation = "^/posts/" + postID + "$"
	comment.PostData = map[string]string{
		"post_id":    postID,
		"comment":    sentence,
		"csrf_token": csrfToken,
	}
	comment.Play(s)
}
Exemple #2
0
// ログインすると右上にアカウント名が出て、ログインしないとアカウント名が出ない
// 画像のキャッシュにSet-Cookieを含んでいた場合、/にアカウント名が含まれる
func loginScenario(s *checker.Session, me user) {
	var imageUrls []string

	login := checker.NewAction("POST", "/login")
	login.ExpectedLocation = `^/$`
	login.Description = "ログインするとユーザー名が表示されること"
	login.PostData = map[string]string{
		"account_name": me.AccountName,
		"password":     me.Password,
	}
	login.CheckFunc = checkHTML(func(doc *goquery.Document) error {

		imageUrls = extractImages(doc)

		name := doc.Find(`.isu-account-name`).Text()
		if name == "" {
			return errors.New("ユーザー名が表示されていません")
		} else if name != me.AccountName {
			return errors.New("表示されているユーザー名が正しくありません")
		}
		return nil
	})
	err := login.Play(s)
	if err != nil {
		return
	}

	loadAssets(s)
	loadImages(s, imageUrls) // この画像へのアクセスでSet-Cookieされてたら失敗する

	logout := checker.NewAction("GET", "/logout")
	logout.ExpectedLocation = `^/$`
	logout.Description = "ログアウトするとユーザー名が表示されないこと"
	logout.CheckFunc = checkHTML(func(doc *goquery.Document) error {

		imageUrls = extractImages(doc)

		name := doc.Find(`.isu-account-name`).Text()
		if name != "" {
			return errors.New("ログアウトしてもユーザー名が表示されています")
		}
		return nil
	})
	err = logout.Play(s)
	if err != nil {
		return
	}

	loadAssets(s)
	loadImages(s, imageUrls)
}
Exemple #3
0
// インデックスにリクエストして「もっと見る」を最大10ページ辿る
// WaitAfterTimeout秒たったら問答無用で打ち切る
func indexMoreAndMoreScenario(s *checker.Session) {
	var imageUrls []string
	start := time.Now()

	imagePerPageChecker := checkHTML(func(doc *goquery.Document) error {
		imageUrls = extractImages(doc)
		if len(imageUrls) < PostsPerPage {
			return errors.New("1ページに表示される画像の数が足りません")
		}
		return nil
	})

	index := checker.NewAction("GET", "/")
	index.ExpectedLocation = `^/$`
	index.Description = "インデックスページが表示できること"
	index.CheckFunc = imagePerPageChecker
	err := index.Play(s)
	if err != nil {
		return
	}

	loadAssets(s)
	loadImages(s, imageUrls)

	offset := util.RandomNumber(10) // 10は適当。URLをバラけさせるため
	for i := 0; i < 10; i++ {       // 10ページ辿る
		maxCreatedAt := time.Date(2016, time.January, 2, 11, 46, 21-PostsPerPage*i+offset, 0, time.FixedZone("Asia/Tokyo", 9*60*60))

		imageUrls = []string{}
		posts := checker.NewAction("GET", "/posts?max_created_at="+url.QueryEscape(maxCreatedAt.Format(time.RFC3339)))
		posts.Description = "インデックスページの「もっと見る」が表示できること"
		posts.CheckFunc = imagePerPageChecker
		err := posts.Play(s)
		if err != nil {
			return
		}

		loadImages(s, imageUrls)

		if time.Now().Sub(start) > WaitAfterTimeout {
			break
		}
	}
}
Exemple #4
0
// 管理者ユーザーでないなら /admin/banned にアクセスできない
func cannotAccessAdminScenario(s *checker.Session, me user) {
	login := checker.NewAction("POST", "/login")
	login.ExpectedLocation = `^/$`
	login.Description = "Adminユーザーでログインできること"

	login.PostData = map[string]string{
		"account_name": me.AccountName,
		"password":     me.Password,
	}
	err := login.Play(s)
	if err != nil {
		return
	}

	adminPage := checker.NewAction("GET", "/admin/banned")
	adminPage.ExpectedStatusCode = http.StatusForbidden

	adminPage.Play(s)
}
Exemple #5
0
// /@:account_name のページにアクセスして投稿ページをいくつか開いていく
// WaitAfterTimeout秒たったら問答無用で打ち切る
func userAndPostPageScenario(s *checker.Session, accountName string) {
	var imageUrls []string
	var postLinks []string
	start := time.Now()

	userPage := checker.NewAction("GET", "/@"+accountName)
	userPage.Description = "ユーザーページ"
	userPage.CheckFunc = checkHTML(func(doc *goquery.Document) error {
		imageUrls = extractImages(doc)
		postLinks = extractPostLinks(doc)
		return nil
	})
	err := userPage.Play(s)
	if err != nil {
		return
	}

	loadAssets(s)
	loadImages(s, imageUrls)

	for _, link := range postLinks {
		postPage := checker.NewAction("GET", link)
		postPage.Description = "投稿単体ページが表示できること"
		postPage.CheckFunc = checkHTML(func(doc *goquery.Document) error {
			imageUrls = extractImages(doc)
			if len(imageUrls) < 1 {
				return errors.New("投稿単体ページに投稿画像が表示されていません")
			}
			return nil
		})
		err := postPage.Play(s)
		if err != nil {
			return
		}

		loadAssets(s)
		loadImages(s, imageUrls)

		if time.Now().Sub(start) > WaitAfterTimeout {
			break
		}
	}
}
Exemple #6
0
// インデックスページを5回表示するだけ(負荷かける用)
// WaitAfterTimeout秒たったら問答無用で打ち切る
func loadIndexScenario(s *checker.Session) {
	var imageUrls []string
	start := time.Now()

	imagePerPageChecker := checkHTML(func(doc *goquery.Document) error {
		imageUrls = extractImages(doc)
		if len(imageUrls) < PostsPerPage {
			return errors.New("1ページに表示される画像の数が足りません")
		}
		return nil
	})

	index := checker.NewAction("GET", "/")
	index.ExpectedLocation = `^/$`
	index.Description = "インデックスページが表示できること"
	index.CheckFunc = imagePerPageChecker
	err := index.Play(s)
	if err != nil {
		return
	}

	loadAssets(s)
	loadImages(s, imageUrls)

	for i := 0; i < 4; i++ {
		// あとの4回はDOMをパースしない。トップページをキャッシュして超高速に返されたとき対策
		index := checker.NewAction("GET", "/")
		index.ExpectedLocation = `^/$`
		index.Description = "インデックスページが表示できること"
		err := index.Play(s)
		if err != nil {
			return
		}

		loadAssets(s)
		loadImages(s, imageUrls) // 画像は初回と同じものにリクエスト投げる

		if time.Now().Sub(start) > WaitAfterTimeout {
			break
		}
	}
}
Exemple #7
0
// ログインして画像を投稿する
// 簡略化のために画像や静的ファイルへのアクセスはスキップする
func postImageScenario(s *checker.Session, me user, image *checker.Asset, sentence string) {
	var csrfToken string
	var imageUrls []string
	var ok bool

	login := checker.NewAction("POST", "/login")
	login.ExpectedLocation = `^/$`
	login.Description = "ログインできること"
	login.PostData = map[string]string{
		"account_name": me.AccountName,
		"password":     me.Password,
	}
	login.CheckFunc = checkHTML(func(doc *goquery.Document) error {

		csrfToken, ok = doc.Find(`input[name="csrf_token"]`).First().Attr("value")
		if !ok {
			return errors.New("CSRFトークンが取得できません")
		}

		return nil
	})
	err := login.Play(s)
	if err != nil {
		return
	}

	postImage := checker.NewUploadAction("POST", "/", "file")
	postImage.Description = "画像を投稿してリダイレクトされること"
	postImage.ExpectedLocation = `^/posts/\d+$`
	postImage.Asset = image
	postImage.PostData = map[string]string{
		"body":       sentence,
		"csrf_token": csrfToken,
	}
	postImage.CheckFunc = checkHTML(func(doc *goquery.Document) error {
		imageUrls = extractImages(doc)
		if len(imageUrls) < 1 {
			return errors.New("投稿した画像が表示されていません")
		}
		return nil
	})
	postImage.Play(s)

	getImage := checker.NewAssetAction(imageUrls[0], image)
	getImage.Description = "投稿した画像と一致すること"
	getImage.Play(s)
}
Exemple #8
0
// 誤ったパスワードでログインできない
func cannotLoginWrongPasswordScenario(s *checker.Session, me user) {
	fakeUser := map[string]string{
		"account_name": me.AccountName,
		"password":     util.RandomLUNStr(util.RandomNumber(15) + 10),
	}

	login := checker.NewAction("POST", "/login")
	login.Description = "間違ったパスワードでログインできないこと"
	login.ExpectedLocation = `^/login$`
	login.PostData = fakeUser
	login.CheckFunc = checkHTML(func(doc *goquery.Document) error {

		message := strings.TrimSpace(doc.Find(`#notice-message`).Text())
		if message != "アカウント名かパスワードが間違っています" {
			return errors.New("ログインエラーメッセージが表示されていません")
		}
		return nil
	})

	login.Play(s)
}
Exemple #9
0
// 間違ったCSRF Tokenで画像を投稿できない
func cannotPostWrongCSRFTokenScenario(s *checker.Session, me user, image *checker.Asset) {
	login := checker.NewAction("POST", "/login")
	login.ExpectedLocation = `^/$`
	login.Description = "正しくログインできること"

	login.PostData = map[string]string{
		"account_name": me.AccountName,
		"password":     me.Password,
	}
	err := login.Play(s)
	if err != nil {
		return
	}

	postImage := checker.NewUploadAction("POST", "/", "file")
	postImage.ExpectedStatusCode = 422
	postImage.Description = "間違ったCSRFトークンでは画像を投稿できないこと"
	postImage.Asset = image
	postImage.PostData = map[string]string{
		"body":       util.RandomLUNStr(25),
		"csrf_token": util.RandomLUNStr(64),
	}
	postImage.Play(s)
}
Exemple #10
0
// 新規登録→画像投稿→banされる
func banScenario(s1, s2 *checker.Session, u user, admin user, image *checker.Asset, sentence string) {
	var csrfToken string
	var imageUrls []string
	var userID string
	var ok bool
	accountName := util.RandomLUNStr(25)
	password := util.RandomLUNStr(25)

	register := checker.NewAction("POST", "/register")
	register.ExpectedLocation = `^/$`
	register.Description = "新規登録できること"
	register.PostData = map[string]string{
		"account_name": accountName,
		"password":     password,
	}
	register.CheckFunc = checkHTML(func(doc *goquery.Document) error {
		name := doc.Find(`.isu-account-name`).Text()
		if name == "" {
			return errors.New("ユーザー名が表示されていません")
		} else if name != accountName {
			return errors.New("表示されているユーザー名が正しくありません")
		}
		csrfToken, ok = doc.Find(`input[name="csrf_token"]`).First().Attr("value")
		if !ok {
			return errors.New("CSRFトークンが取得できません")
		}

		return nil
	})
	err := register.Play(s1)
	if err != nil {
		return
	}

	postImage := checker.NewUploadAction("POST", "/", "file")
	postImage.Description = "画像を投稿してリダイレクトされること"
	postImage.ExpectedLocation = `^/posts/\d+$`
	postImage.Asset = image
	postImage.PostData = map[string]string{
		"body":       util.RandomLUNStr(15),
		"csrf_token": csrfToken,
	}
	postImage.CheckFunc = checkHTML(func(doc *goquery.Document) error {
		imageUrls = extractImages(doc)
		if len(imageUrls) < 1 {
			return errors.New("投稿した画像が表示されていません")
		}
		return nil
	})

	if len(imageUrls) < 1 {
		return // このケースは上のCheckFuncの中で既にエラーにしてある
	}

	imageUrl := imageUrls[0]

	getImage := checker.NewAssetAction(imageUrl, image)
	getImage.Description = "投稿した画像と一致することを確認"
	err = getImage.Play(s1)
	if err != nil {
		return
	}

	login := checker.NewAction("POST", "/login")
	login.ExpectedLocation = `^/$`
	login.Description = "管理ユーザーでログインできること"
	login.PostData = map[string]string{
		"account_name": admin.AccountName,
		"password":     admin.Password,
	}
	login.CheckFunc = checkHTML(func(doc *goquery.Document) error {
		imageUrls = extractImages(doc)
		for _, url := range imageUrls {
			if url == imageUrl {
				return nil // 投稿した画像が正しく表示されている
			}
		}
		return errors.New("投稿した画像が表示されていません")
	})
	err = login.Play(s2)
	if err != nil {
		return
	}

	banPage := checker.NewAction("GET", "/admin/banned")
	banPage.Description = "管理ユーザーが管理ページにアクセスできること"
	banPage.ExpectedLocation = `^/admin/banned$`
	banPage.CheckFunc = checkHTML(func(doc *goquery.Document) error {
		csrfToken, ok = doc.Find(`input[name="csrf_token"]`).First().Attr("value")
		if !ok {
			return errors.New("CSRFトークンが取得できません")
		}
		userID, ok = doc.Find(`input[data-account-name="` + accountName + `"]`).First().Attr("value")
		if !ok {
			return errors.New("新規登録されたユーザーが管理ページに表示されていません")
		}
		return nil
	})
	err = banPage.Play(s2)
	if err != nil {
		return
	}

	ban := checker.NewAction("POST", "/admin/banned")
	ban.Description = "ユーザーの禁止ができること"
	ban.ExpectedLocation = `^/admin/banned$`
	ban.PostData = map[string]string{
		"uid[]":      userID,
		"csrf_token": csrfToken,
	}
	err = ban.Play(s2)
	if err != nil {
		return
	}

	index := checker.NewAction("GET", "/")
	index.Description = "トップページに禁止ユーザーの画像が表示されていないこと"
	index.CheckFunc = checkHTML(func(doc *goquery.Document) error {
		imageUrls = extractImages(doc)
		for _, url := range imageUrls {
			if url == imageUrl {
				return errors.New("禁止ユーザーの画像が表示されています")
			}
		}
		return nil
	})
	index.Play(s2)
}