tarakan/test/support/github_stubs.ex
Maxfield Luke af6077b9c3
All checks were successful
CI and deploy / Test (push) Successful in 4m52s
CI and deploy / Deploy production (push) Successful in 23s
Initial commit on Forgejo
Fresh repository history for elektrine/tarakan hosted at
https://git.elektrine.com/elektrine/tarakan.
2026-07-29 04:43:40 -04:00

449 lines
13 KiB
Elixir

defmodule Tarakan.GitHubStub do
@moduledoc false
@behaviour Tarakan.GitHubClient
@root_tree_sha String.duplicate("1", 40)
@lib_tree_sha String.duplicate("2", 40)
@readme_blob_sha String.duplicate("3", 40)
@source_blob_sha String.duplicate("4", 40)
@large_blob_sha String.duplicate("5", 40)
@binary_blob_sha String.duplicate("6", 40)
@default_commit_sha String.duplicate("7", 40)
@symlink_blob_sha String.duplicate("9", 40)
@submodule_sha String.duplicate("a", 40)
@many_lines_blob_sha String.duplicate("d", 40)
@truncated_tree_sha String.duplicate("e", 40)
@unsafe_html_blob_sha String.duplicate("f", 40)
@readme "# Codex\n"
@source "defmodule Codex do\n def hello, do: :world\nend\n"
@unsafe_html "</code><script id=\"source-xss\">alert(1)</script>\n"
@codex_etag ~s(W/"codex-metadata")
def codex_etag, do: @codex_etag
@impl true
def fetch_repository(owner, name, opts \\ [])
def fetch_repository("openai", "codex", opts) do
if Keyword.get(opts, :etag) == @codex_etag do
:not_modified
else
{:ok,
%{
github_id: 95_959_834,
node_id: "R_kgDOcodex000",
host: "github.com",
owner: "openai",
name: "codex",
canonical_url: "https://github.com/openai/codex",
default_branch: "main",
description: "Lightweight coding agent that runs in your terminal",
primary_language: "Rust",
stars_count: 42_000,
forks_count: 4_200,
archived: false,
private: false,
visibility: "public",
last_synced_at: ~U[2026-07-10 04:00:00.000000Z],
etag: @codex_etag
}}
end
end
def fetch_repository("missing", "repository", _opts), do: {:error, :not_found}
# Renamed on the host: the old path 301s, the immutable id resolves to acme/widget.
def fetch_repository("legacy", "widget", _opts), do: {:error, :moved}
def fetch_repository("acme", "widget", _opts), do: {:ok, renamed_widget_metadata()}
def fetch_repository("acme", "gadget", _opts) do
{:ok,
%{
github_id: 77_778,
node_id: "R_kgDOgadget00",
host: "github.com",
owner: "acme",
name: "gadget",
canonical_url: "https://github.com/acme/gadget",
default_branch: "main",
description: "Gadget toolkit",
primary_language: "Go",
stars_count: 21,
forks_count: 2,
archived: false,
private: false,
visibility: "public",
last_synced_at: ~U[2026-07-10 04:00:00.000000Z]
}}
end
def fetch_repository("private", "repository", _opts) do
{:ok,
%{
github_id: 12_345,
host: "github.com",
owner: "private",
name: "repository",
canonical_url: "https://github.com/private/repository",
default_branch: "main",
private: true,
visibility: "private"
}}
end
def fetch_repository("rate", "limited", _opts), do: {:error, :rate_limited}
def fetch_repository("flip", "repository", _opts) do
count = Process.get(:github_flip_identity_count, 0)
Process.put(:github_flip_identity_count, count + 1)
if count == 0 do
{:ok,
%{
github_id: 88_888,
host: "github.com",
owner: "flip",
name: "repository",
canonical_url: "https://github.com/flip/repository",
default_branch: "main",
private: false,
visibility: "public"
}}
else
{:ok,
%{
github_id: 88_888,
owner: "flip",
name: "repository",
default_branch: "main",
private: true,
visibility: "private"
}}
end
end
def fetch_repository("lateflip", "repository", _opts) do
count = Process.get(:github_late_flip_identity_count, 0)
Process.put(:github_late_flip_identity_count, count + 1)
if count < 3 do
{:ok,
%{
github_id: 99_999,
host: "github.com",
owner: "lateflip",
name: "repository",
canonical_url: "https://github.com/lateflip/repository",
default_branch: "main",
private: false,
visibility: "public"
}}
else
{:ok,
%{
github_id: 99_999,
owner: "lateflip",
name: "repository",
default_branch: "main",
private: true,
visibility: "private"
}}
end
end
def fetch_repository(_owner, _name, _opts), do: {:error, :unavailable}
@impl true
def fetch_repository_by_id(95_959_834), do: fetch_repository("openai", "codex", [])
def fetch_repository_by_id(12_345), do: fetch_repository("private", "repository", [])
def fetch_repository_by_id(88_888), do: fetch_repository("flip", "repository", [])
def fetch_repository_by_id(99_999), do: fetch_repository("lateflip", "repository", [])
def fetch_repository_by_id(77_777), do: {:ok, renamed_widget_metadata()}
def fetch_repository_by_id(_github_id), do: {:error, :not_found}
defp renamed_widget_metadata do
%{
github_id: 77_777,
node_id: "R_kgDOwidget00",
host: "github.com",
owner: "acme",
name: "widget",
canonical_url: "https://github.com/acme/widget",
default_branch: "main",
description: "Widget toolkit",
primary_language: "Elixir",
stars_count: 12,
forks_count: 3,
archived: false,
private: false,
visibility: "public",
last_synced_at: ~U[2026-07-10 04:00:00.000000Z]
}
end
@impl true
def fetch_commit("openai", "codex", "dead" <> _rest), do: {:error, :not_found}
def fetch_commit("openai", "codex", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") do
{:ok,
%{
sha: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
tree_sha: @root_tree_sha,
committed_at: ~U[2026-07-01 12:00:00Z]
}}
end
def fetch_commit("openai", "codex", "cccccccccccccccccccccccccccccccccccccccc") do
{:ok,
%{
sha: "cccccccccccccccccccccccccccccccccccccccc",
tree_sha: @truncated_tree_sha,
committed_at: ~U[2026-07-01 12:00:00Z]
}}
end
# Second precision, mirroring what the GitHub API actually returns.
def fetch_commit("openai", "codex", sha),
do:
{:ok,
%{
sha: String.downcase(sha),
tree_sha: @root_tree_sha,
committed_at: ~U[2026-07-01 12:00:00Z]
}}
def fetch_commit("acme", "widget", sha), do: fetch_commit("openai", "codex", sha)
def fetch_commit("acme", "gadget", sha), do: fetch_commit("openai", "codex", sha)
def fetch_commit("rate", "limited", _sha), do: {:error, :rate_limited}
def fetch_commit("flip", "repository", sha), do: fetch_commit("openai", "codex", sha)
def fetch_commit("lateflip", "repository", sha), do: fetch_commit("openai", "codex", sha)
def fetch_commit(_owner, _name, _sha), do: {:error, :unavailable}
@impl true
def fetch_branch_head("openai", "codex", "main") do
{:ok,
%{
sha: @default_commit_sha,
tree_sha: @root_tree_sha,
committed_at: ~U[2026-07-01 12:00:00Z]
}}
end
def fetch_branch_head("openai", "codex", "develop") do
{:ok,
%{
sha: String.duplicate("8", 40),
tree_sha: @root_tree_sha,
committed_at: ~U[2026-07-02 12:00:00Z]
}}
end
def fetch_branch_head("acme", "widget", branch),
do: fetch_branch_head("openai", "codex", branch)
def fetch_branch_head("acme", "gadget", branch),
do: fetch_branch_head("openai", "codex", branch)
def fetch_branch_head("rate", "limited", _branch), do: {:error, :rate_limited}
def fetch_branch_head(_owner, _name, _branch), do: {:error, :not_found}
@impl true
def list_branches("openai", "codex"), do: {:ok, ["main", "develop", "feature/auth"]}
def list_branches("acme", "widget"), do: list_branches("openai", "codex")
def list_branches("acme", "gadget"), do: list_branches("openai", "codex")
def list_branches("rate", "limited"), do: {:error, :rate_limited}
def list_branches(_owner, _name), do: {:error, :not_found}
@impl true
def fetch_tree("openai", "codex", @root_tree_sha, recursive) do
direct_entries = [
%{path: "lib", mode: "040000", type: "tree", sha: @lib_tree_sha, size: nil},
%{
path: "README.md",
mode: "100644",
type: "blob",
sha: @readme_blob_sha,
size: byte_size(@readme)
},
%{
path: "space # 100%.txt",
mode: "100644",
type: "blob",
sha: @readme_blob_sha,
size: byte_size(@readme)
},
%{
path: "λ.ex",
mode: "100644",
type: "blob",
sha: @source_blob_sha,
size: byte_size(@source)
},
%{
path: "large.txt",
mode: "100644",
type: "blob",
sha: @large_blob_sha,
size: 512 * 1_024 + 1
},
%{
path: "binary.dat",
mode: "100644",
type: "blob",
sha: @binary_blob_sha,
size: 4
},
%{
path: "many-lines.txt",
mode: "100644",
type: "blob",
sha: @many_lines_blob_sha,
size: 10_000
},
%{
path: "unsafe.html",
mode: "100644",
type: "blob",
sha: @unsafe_html_blob_sha,
size: byte_size(@unsafe_html)
},
%{
path: "source-link",
mode: "120000",
type: "symlink",
sha: @symlink_blob_sha,
size: 12
},
%{
path: "dependency",
mode: "160000",
type: "submodule",
sha: @submodule_sha,
size: nil
}
]
entries =
if recursive do
direct_entries ++
[
%{
path: "lib/codex.ex",
mode: "100644",
type: "blob",
sha: @source_blob_sha,
size: byte_size(@source)
}
]
else
direct_entries
end
{:ok, %{sha: @root_tree_sha, truncated: false, entries: entries}}
end
def fetch_tree("openai", "codex", @lib_tree_sha, _recursive) do
{:ok,
%{
sha: @lib_tree_sha,
truncated: false,
entries: [
%{
path: "codex.ex",
mode: "100644",
type: "blob",
sha: @source_blob_sha,
size: byte_size(@source)
}
]
}}
end
def fetch_tree("openai", "codex", @truncated_tree_sha, _recursive) do
{:ok, %{sha: @truncated_tree_sha, truncated: true, entries: []}}
end
def fetch_tree("acme", "widget", tree_sha, recursive),
do: fetch_tree("openai", "codex", tree_sha, recursive)
def fetch_tree("acme", "gadget", tree_sha, recursive),
do: fetch_tree("openai", "codex", tree_sha, recursive)
def fetch_tree("rate", "limited", _tree_sha, _recursive), do: {:error, :rate_limited}
def fetch_tree("flip", "repository", tree_sha, recursive),
do: fetch_tree("openai", "codex", tree_sha, recursive)
def fetch_tree("lateflip", "repository", tree_sha, recursive),
do: fetch_tree("openai", "codex", tree_sha, recursive)
def fetch_tree(_owner, _name, _tree_sha, _recursive), do: {:error, :not_found}
@impl true
def fetch_text_blob("openai", "codex", @readme_blob_sha) do
{:ok, %{sha: @readme_blob_sha, size: byte_size(@readme), content: @readme}}
end
def fetch_text_blob("openai", "codex", @source_blob_sha) do
{:ok, %{sha: @source_blob_sha, size: byte_size(@source), content: @source}}
end
def fetch_text_blob("openai", "codex", @binary_blob_sha) do
{:ok, %{sha: @binary_blob_sha, size: 4, content: <<0, 1, 2, 3>>}}
end
def fetch_text_blob("openai", "codex", @many_lines_blob_sha) do
content = String.duplicate("\n", 10_000)
{:ok, %{sha: @many_lines_blob_sha, size: byte_size(content), content: content}}
end
def fetch_text_blob("openai", "codex", @unsafe_html_blob_sha) do
{:ok,
%{
sha: @unsafe_html_blob_sha,
size: byte_size(@unsafe_html),
content: @unsafe_html
}}
end
def fetch_text_blob("openai", "codex", @large_blob_sha), do: {:error, :unavailable}
def fetch_text_blob("acme", "widget", blob_sha),
do: fetch_text_blob("openai", "codex", blob_sha)
def fetch_text_blob("acme", "gadget", blob_sha),
do: fetch_text_blob("openai", "codex", blob_sha)
def fetch_text_blob("rate", "limited", _blob_sha), do: {:error, :rate_limited}
def fetch_text_blob(_owner, _name, _blob_sha), do: {:error, :not_found}
end
defmodule Tarakan.GitHub.OAuthStub do
@moduledoc false
@behaviour Tarakan.GitHub.OAuthClient
@impl true
def exchange_code("valid-code", verifier, redirect_uri)
when is_binary(verifier) and is_binary(redirect_uri),
do: {:ok, "temporary-user-token"}
def exchange_code(_code, _verifier, _redirect_uri), do: {:error, :authorization_failed}
@impl true
def fetch_user("temporary-user-token") do
{:ok,
%{
provider_uid: 58_399_067,
provider_login: "TarakanTester",
name: "Tarakan Tester",
avatar_url: "https://avatars.githubusercontent.com/u/58399067",
profile_url: "https://github.com/TarakanTester"
}}
end
def fetch_user(_token), do: {:error, :authorization_failed}
end