Skip to content
quarry Artifact [7a9058cd04]
Login

Artifact [7a9058cd04]

Artifact 7a9058cd04eb87fe93b02575dd0ee83cae471a28f40699e305574dbcd3c9a2fa:


package oltp

import (
	"path/filepath"
	"testing"
	"time"
)

func chatOf(t *testing.T, d *DB, name string) bool {
	t.Helper()
	var on bool
	if err := d.db.QueryRow(`SELECT chat FROM repo WHERE name = ?`, name).Scan(&on); err != nil {
		t.Fatalf("chat of %s: %v", name, err)
	}
	return on
}

// A store that becomes a tracking mirror starts with chat off. An admin's
// choice survives a change of interval, and re-attaching after a detach
// starts over, the way accept_writes does.
func TestBecomingAMirrorTurnsChatOff(t *testing.T) {
	d := openTest(t)
	if err := d.AddRepo("m", "/tmp/m", "", "public"); err != nil {
		t.Fatal(err)
	}
	if !chatOf(t, d, "m") {
		t.Fatal("a native repository does not start with chat on")
	}
	if err := d.SetMirror("m", "https://up.example/m", time.Hour); err != nil {
		t.Fatal(err)
	}
	if chatOf(t, d, "m") {
		t.Fatal("becoming a mirror left chat on")
	}
	if err := d.SetRepoChat("m", true); err != nil {
		t.Fatal(err)
	}
	if err := d.SetMirror("m", "https://up.example/m", 2*time.Hour); err != nil {
		t.Fatal(err)
	}
	if !chatOf(t, d, "m") {
		t.Fatal("changing the interval undid the admin's chat setting")
	}
	if err := d.DetachMirror("m"); err != nil {
		t.Fatal(err)
	}
	if !chatOf(t, d, "m") {
		t.Fatal("detaching changed the chat setting")
	}
	if err := d.SetMirror("m", "https://up.example/m", time.Hour); err != nil {
		t.Fatal(err)
	}
	if chatOf(t, d, "m") {
		t.Fatal("re-attaching kept chat on from the previous posture")
	}
}

// Setting a chat bridge is syndicating the upstream's chat, which only
// means anything with the channel on.
func TestAChatBridgeTurnsChatOn(t *testing.T) {
	d := openTest(t)
	if err := d.AddRepo("z", "/tmp/z", "", "public"); err != nil {
		t.Fatal(err)
	}
	if err := d.SetMirror("z", "https://up.example/z", time.Hour); err != nil {
		t.Fatal(err)
	}
	if chatOf(t, d, "z") {
		t.Fatal("precondition: a fresh mirror has chat off")
	}
	if err := d.SetChatBridge("z", "https://up.example/z", "bot", "secret"); err != nil {
		t.Fatal(err)
	}
	if !chatOf(t, d, "z") {
		t.Fatal("a bridge did not turn chat on")
	}
}

// Mirrors registered before this default existed have chat on because
// the column said so. One open turns them off, unless a bridge says the
// channel is in use; a later open does not undo what an admin chose.
func TestExistingMirrorsLoseChatOnceUnlessBridged(t *testing.T) {
	path := filepath.Join(t.TempDir(), "oltp.db")
	d, err := Open(path)
	if err != nil {
		t.Fatal(err)
	}
	for _, name := range []string{"plain", "bridged", "native"} {
		if err := d.AddRepo(name, "/tmp/"+name, "", "public"); err != nil {
			t.Fatal(err)
		}
	}
	for _, name := range []string{"plain", "bridged"} {
		if err := d.SetMirror(name, "https://up.example/"+name, time.Hour); err != nil {
			t.Fatal(err)
		}
		// The world before the default: every mirror had chat on.
		if _, err := d.db.Exec(`UPDATE repo SET chat = 1 WHERE name = ?`, name); err != nil {
			t.Fatal(err)
		}
	}
	if err := d.SetChatBridge("bridged", "https://up.example/bridged", "bot", "s"); err != nil {
		t.Fatal(err)
	}
	// This database was opened fresh above, so the migration already
	// ran (over nothing) and recorded itself; forget that, as a database
	// from before the migration existed would have nothing recorded.
	if _, err := d.db.Exec(`DELETE FROM applied_migration WHERE name = 'mirror-chat-off'`); err != nil {
		t.Fatal(err)
	}
	d.Close()

	d, err = Open(path)
	if err != nil {
		t.Fatal(err)
	}
	if chatOf(t, d, "plain") {
		t.Error("an unbridged mirror kept chat on across the migration")
	}
	if !chatOf(t, d, "bridged") {
		t.Error("a bridged mirror lost its chat")
	}
	if !chatOf(t, d, "native") {
		t.Error("a native repository lost its chat")
	}
	// The admin turns it back on; the next open must not run again.
	if err := d.SetRepoChat("plain", true); err != nil {
		t.Fatal(err)
	}
	d.Close()
	d, err = Open(path)
	if err != nil {
		t.Fatal(err)
	}
	defer d.Close()
	if !chatOf(t, d, "plain") {
		t.Error("the migration ran a second time and undid the admin's choice")
	}
}