Skip to content

Conversation

@gocanto
Copy link
Collaborator

@gocanto gocanto commented Aug 5, 2025

Summary

  • remove categories and posts repository interfaces
  • inject repository behavior through function parameters
  • adjust router and tests to use new function-based handlers

Testing

  • go test ./...

https://chatgpt.com/codex/tasks/task_e_6891a96294d48333bcfa9ae297adbd97

Summary by CodeRabbit

  • Refactor

    • Updated handler dependencies to use concrete repository types instead of interfaces for categories and posts.
  • Tests

    • Added comprehensive tests for categories, posts, projects, recommendations, social, talks, education, experience, profile, and related payloads.
    • Introduced reusable test framework and helper utilities for managing test data and file-based handlers.
    • Added integration tests with PostgreSQL Docker container setup for reliable database testing.
    • Removed outdated or redundant test files and functions to streamline test suite.
  • Chores

    • Updated dependency declarations for improved clarity.

@coderabbitai
Copy link

coderabbitai bot commented Aug 5, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Warning

Rate limit exceeded

@gocanto has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 4 minutes and 54 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 097210a and 59b2783.

📒 Files selected for processing (1)
  • handler/tests/db.go (1 hunks)

Walkthrough

This change refactors handler dependencies from interfaces to concrete repository types for categories and posts, updates their constructors, and replaces or restructures related tests. Several new, more comprehensive integration and unit tests are introduced for handlers and payloads, while older or redundant test files are removed. Test helpers are added for JSON file management and database setup.

Changes

Cohort / File(s) Change Summary
Handler Interface Refactor
handler/categories.go, handler/posts.go
Removed repository interfaces from handlers, switched handler fields and constructors to use concrete *repository.Categories and *repository.Posts types.
Handler Test Refactor & Expansion
handler/categories_posts_test.go, handler/categories_test.go, handler/posts_test.go, handler/projects_test.go, handler/recommendations_test.go, handler/talks_test.go, handler/education_test.go, handler/experience_test.go, handler/social_test.go, handler/profile_test.go
Deleted old handler tests using stubs; added new integration and unit tests for each handler, using testcontainers for DB-backed handlers and temp files for file-backed handlers. Updated test logic for better coverage and payload checks.
Payload Test Additions & Moves
handler/payload/categories_test.go, handler/payload/tags_test.go, handler/payload/posts_filters_test.go, handler/payload/posts_slug_test.go, handler/payload/posts_response_test.go, handler/payload/education_test.go, handler/payload/experience_test.go, handler/payload/projects_test.go, handler/payload/recommendations_test.go, handler/payload/social_test.go, handler/payload/talks_test.go, handler/payload/users_test.go, handler/payload/profile_test.go
Added or moved payload tests for JSON marshaling/unmarshaling and utility functions. Some tests were relocated or split for clarity. Redundant or relocated tests were removed.
Test Helper Utilities
handler/tests/helpers.go, handler/tests/helpers_test.go, handler/file_handler_test.go, handler/tests/db.go
Added a generic test envelope struct and helper for writing JSON files; introduced a reusable file handler test framework; added a test helper to provision a PostgreSQL test database using testcontainers and run migrations.
Dependency Declaration
go.mod
Moved github.com/rs/cors from indirect to direct dependency.
File-backed Handler Test Cleanup
handler/file_handlers_more_test.go
Deleted legacy test for file-backed handlers, replaced by new, more focused tests using the new test framework.

Sequence Diagram(s)

sequenceDiagram
    participant Test as Test Function
    participant Handler as Handler (e.g., PostsHandler)
    participant Repo as Repository (e.g., *repository.Posts)
    participant DB as Test DB / File

    Test->>Repo: Setup test data (DB or file)
    Test->>Handler: Construct handler with Repo
    Test->>Handler: Send HTTP request (e.g., GET /posts)
    Handler->>Repo: Query for data (DB or file)
    Repo->>DB: Fetch data
    DB-->>Repo: Return data
    Repo-->>Handler: Return data
    Handler-->>Test: Write HTTP response (JSON)
    Test->>Test: Assert response correctness
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • [feature] Get Posts/Post #59: Introduced posts feature, including the posts repository and handler, directly related to the handler and repository refactoring in this PR.

Suggested labels

testing

Poem

In the warren of code, the tests multiply,
Old stubs hop away, new helpers draw nigh.
Handlers now munch on concrete, not fluff,
Payloads are checked—no more guesswork or bluff!
With temp files and containers, the garden is neat,
This bunny approves—review is a treat! 🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch hk1dre-codex/remove-categoriesrepo-and-postsrepo-interfaces

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@gocanto gocanto marked this pull request as draft August 5, 2025 07:08
Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary of Changes

Hello @gocanto, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a significant refactoring of the application's dependency injection pattern, moving away from interface-based repository injection towards a more direct function-based approach. This change aims to simplify the handler logic, reduce boilerplate, and streamline testing by directly providing the necessary repository functions rather than abstract interfaces.

Highlights

  • Dependency Injection Strategy Refactor: The pull request refactors the dependency injection mechanism for repository operations within the handler package. Instead of injecting entire repository interfaces, specific repository methods are now injected directly as function parameters into the handler constructors.
  • Removal of Repository Interfaces: The categoriesRepo and postsRepo interfaces have been removed from the handler package. This simplifies the type definitions and reduces an unnecessary layer of abstraction where direct function injection proved more suitable.
  • Handler and Router Adjustments: The CategoriesHandler and PostsHandler structs, along with their Make constructors, have been updated to accept and utilize these directly injected functions (e.g., GetAll, FindBy). Correspondingly, boost/router.go now passes the concrete repository methods (e.g., repo.GetAll, repo.FindBy) when initializing these handlers.
  • Test Suite Simplification: The test files, specifically handler/categories_posts_test.go, have been updated to align with the new function-based injection. The previous stubCategories and stubPosts structs, which implemented the removed interfaces, have been removed and replaced by anonymous functions that directly mock the expected behavior of the injected repository methods, leading to more concise and focused tests.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments or fill out our survey to provide feedback.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the code to remove repository interfaces in favor of passing repository methods as functions directly to the handlers. This is a good simplification that leverages Go's first-class functions for dependency injection, especially suitable for handlers with few dependencies.

My feedback focuses on improving maintainability and readability by using type aliases for long function signatures, and enhancing test clarity and robustness by suggesting table-driven tests and more defensive mocks.

@gocanto gocanto marked this pull request as ready for review August 6, 2025 03:52
@gocanto gocanto marked this pull request as draft August 6, 2025 03:54
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

♻️ Duplicate comments (1)
handler/posts.go (1)

16-22: Refactoring aligns with PR objectives but differs from previous suggestion.

The change from interface abstraction to concrete *repository.Posts type is consistent with the PR's goal of removing repository interfaces. However, this approach differs from the previous review suggestion to use type aliases for function signatures to improve readability.

The current implementation is functionally correct and aligns with the broader refactoring strategy across the codebase.

🧹 Nitpick comments (12)
handler/payload/posts_slug_test.go (1)

8-14: Enhance test coverage and error messages.

The test correctly validates slug normalization, but could be improved:

  1. The error message on line 12 should be more descriptive
  2. Consider adding more test cases for edge cases (empty string, special characters, etc.)

Apply this diff to improve the error message:

-	if s := GetSlugFrom(r); s != "slug" {
-		t.Fatalf("slug %s", s)
-	}
+	if s := GetSlugFrom(r); s != "slug" {
+		t.Fatalf("expected slug 'slug', got '%s'", s)
+	}

Consider adding a table-driven test for better coverage:

func TestGetSlugFrom(t *testing.T) {
	tests := []struct {
		name     string
		slug     string
		expected string
	}{
		{"uppercase with spaces", "  SLUG ", "slug"},
		{"lowercase", "slug", "slug"},
		{"mixed case", "MySlug", "myslug"},
		{"with special chars", "my-slug_123", "my-slug_123"},
	}
	
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			r := httptest.NewRequest("GET", "/posts/s", nil)
			r.SetPathValue("slug", tt.slug)
			if s := GetSlugFrom(r); s != tt.expected {
				t.Fatalf("expected slug '%s', got '%s'", tt.expected, s)
			}
		})
	}
}
handler/payload/social_test.go (1)

8-17: LGTM - Consider improving test data and assertions.

The JSON unmarshaling test is correct and serves its purpose well.

Consider these improvements for better test quality:

  1. Use more realistic test data instead of single characters
  2. Add assertions for all JSON fields to ensure complete unmarshaling
func TestSocialResponseJSON(t *testing.T) {
-	body := []byte(`{"version":"v1","data":[{"uuid":"u","handle":"h","url":"u","description":"d","name":"n"}]}`)
+	body := []byte(`{"version":"v1","data":[{"uuid":"123e4567-e89b-12d3-a456-426614174000","handle":"twitter","url":"https://twitter.com/user","description":"My Twitter profile","name":"Twitter"}]}`)
	var res SocialResponse
	if err := json.Unmarshal(body, &res); err != nil {
		t.Fatalf("unmarshal: %v", err)
	}
-	if res.Version != "v1" || len(res.Data) != 1 || res.Data[0].Name != "n" {
+	if res.Version != "v1" {
+		t.Fatalf("expected version 'v1', got '%s'", res.Version)
+	}
+	if len(res.Data) != 1 {
+		t.Fatalf("expected 1 data item, got %d", len(res.Data))
+	}
+	social := res.Data[0]
+	if social.Name != "Twitter" || social.Handle != "twitter" || social.URL != "https://twitter.com/user" {
-		t.Fatalf("unexpected response: %+v", res)
+		t.Fatalf("unexpected social data: %+v", social)
	}
}
handler/payload/talks_test.go (1)

8-17: LGTM - Similar improvements needed as other payload tests.

The JSON unmarshaling test correctly validates the TalksResponse structure.

As with other payload tests in this PR, consider using more realistic test data and comprehensive field validation:

func TestTalksResponseJSON(t *testing.T) {
-	body := []byte(`{"version":"v1","data":[{"uuid":"u","title":"t","subject":"s","location":"l","url":"u","photo":"p","created_at":"c","updated_at":"up"}]}`)
+	body := []byte(`{"version":"v1","data":[{"uuid":"123e4567-e89b-12d3-a456-426614174000","title":"Go Best Practices","subject":"Programming","location":"San Francisco","url":"https://example.com/talk","photo":"https://example.com/photo.jpg","created_at":"2024-01-01T00:00:00Z","updated_at":"2024-01-02T00:00:00Z"}]}`)
	var res TalksResponse
	if err := json.Unmarshal(body, &res); err != nil {
		t.Fatalf("unmarshal: %v", err)
	}
-	if res.Version != "v1" || len(res.Data) != 1 || res.Data[0].Title != "t" {
+	if res.Version != "v1" {
+		t.Fatalf("expected version 'v1', got '%s'", res.Version)
+	}
+	if len(res.Data) != 1 {
+		t.Fatalf("expected 1 data item, got %d", len(res.Data))
+	}
+	talk := res.Data[0]
+	if talk.Title != "Go Best Practices" || talk.Subject != "Programming" {
-		t.Fatalf("unexpected response: %+v", res)
+		t.Fatalf("unexpected talk data: %+v", talk)
	}
}
handler/payload/tags_test.go (1)

9-15: LGTM - Consider testing all converted fields.

The test correctly validates the GetTagsResponse conversion function.

Consider testing all fields that are converted, not just the Slug:

func TestGetTagsResponse(t *testing.T) {
-	tags := []database.Tag{{UUID: "1", Name: "n", Slug: "s", Description: "d"}}
+	tags := []database.Tag{{
+		UUID:        "123e4567-e89b-12d3-a456-426614174000",
+		Name:        "Technology",
+		Slug:        "technology",
+		Description: "Posts about technology",
+	}}
	r := GetTagsResponse(tags)
-	if len(r) != 1 || r[0].Slug != "s" {
+	if len(r) != 1 {
+		t.Fatalf("expected 1 tag response, got %d", len(r))
+	}
+	tag := r[0]
+	if tag.UUID != "123e4567-e89b-12d3-a456-426614174000" ||
+		tag.Name != "Technology" ||
+		tag.Slug != "technology" ||
+		tag.Description != "Posts about technology" {
-		t.Fatalf("unexpected %#v", r)
+		t.Fatalf("unexpected tag response: %+v", tag)
	}
}

Also consider testing edge cases:

func TestGetTagsResponse_Empty(t *testing.T) {
	tags := []database.Tag{}
	r := GetTagsResponse(tags)
	if len(r) != 0 {
		t.Fatalf("expected empty response, got %d items", len(r))
	}
}
handler/payload/profile_test.go (1)

8-17: Consider improving JSON readability for maintainability.

The test logic is correct and follows good practices. However, the hardcoded JSON string on line 9 is quite long and difficult to read. Consider using a multiline string or formatting for better maintainability.

func TestProfileResponseJSON(t *testing.T) {
-	body := []byte(`{"version":"v1","data":{"nickname":"n","handle":"h","name":"nm","email":"e","profession":"p","skills":[{"uuid":"u","percentage":1,"item":"i","description":"d"}]}}`)
+	body := []byte(`{
+		"version":"v1",
+		"data":{
+			"nickname":"n",
+			"handle":"h",
+			"name":"nm",
+			"email":"e",
+			"profession":"p",
+			"skills":[{"uuid":"u","percentage":1,"item":"i","description":"d"}]
+		}
+	}`)
	var res ProfileResponse
handler/payload/education_test.go (1)

8-17: Consistent test pattern with readability improvement opportunity.

The test correctly validates JSON unmarshalling for EducationResponse and follows the same pattern as other payload tests in this PR. The logic and assertions are appropriate.

Similar to other payload tests, consider formatting the JSON for better readability:

func TestEducationResponseJSON(t *testing.T) {
-	body := []byte(`{"version":"v1","data":[{"uuid":"u","icon":"i","school":"s","degree":"d","field":"f","description":"desc","graduated_at":"g","issuing_country":"c"}]}`)
+	body := []byte(`{
+		"version":"v1",
+		"data":[{
+			"uuid":"u",
+			"icon":"i",
+			"school":"s",
+			"degree":"d",
+			"field":"f",
+			"description":"desc",
+			"graduated_at":"g",
+			"issuing_country":"c"
+		}]
+	}`)
	var res EducationResponse
handler/payload/posts_filters_test.go (1)

5-11: LGTM! Consider adding edge case coverage.

The test correctly validates the field mapping functionality of GetPostsFiltersFrom. The logic is sound and covers all fields.

Consider adding test cases for edge scenarios:

func TestGetPostsFiltersFromEmpty(t *testing.T) {
	req := IndexRequestBody{}
	f := GetPostsFiltersFrom(req)
	if f.Title != "" || f.Author != "" || f.Category != "" || f.Tag != "" || f.Text != "" {
		t.Fatalf("expected empty filters, got: %+v", f)
	}
}
handler/payload/users_test.go (1)

8-17: Well-structured test with room for readability improvement.

The test effectively validates JSON unmarshalling for UserResponse, including proper testing of the boolean IsAdmin field. The logic and error handling are correct.

For consistency with other payload tests and better maintainability, consider formatting the JSON:

func TestUserResponseJSON(t *testing.T) {
-	body := []byte(`{"uuid":"u","first_name":"f","last_name":"l","username":"un","display_name":"dn","bio":"b","picture_file_name":"p","profile_picture_url":"pu","is_admin":true}`)
+	body := []byte(`{
+		"uuid":"u",
+		"first_name":"f",
+		"last_name":"l",
+		"username":"un",
+		"display_name":"dn",
+		"bio":"b",
+		"picture_file_name":"p",
+		"profile_picture_url":"pu",
+		"is_admin":true
+	}`)
	var res UserResponse
handler/payload/recommendations_test.go (1)

8-17: Consider improving test readability and coverage.

The test function is functionally correct but could benefit from improvements:

  1. The JSON string on line 9 is quite long and hard to read
  2. Single-character test values (like "u", "r", "t") make it difficult to verify correct field mapping
  3. Consider testing more fields to ensure comprehensive JSON unmarshalling
func TestRecommendationsResponseJSON(t *testing.T) {
-	body := []byte(`{"version":"v1","data":[{"uuid":"u","relation":"r","text":"t","created_at":"c","updated_at":"u","person":{"avatar":"a","full_name":"f","company":"co","designation":"d"}}]}`)
+	body := []byte(`{
+		"version":"v1",
+		"data":[{
+			"uuid":"test-uuid",
+			"relation":"colleague",
+			"text":"Great to work with",
+			"created_at":"2023-01-01",
+			"updated_at":"2023-01-02",
+			"person":{
+				"avatar":"avatar-url",
+				"full_name":"John Doe",
+				"company":"Tech Corp",
+				"designation":"Senior Developer"
+			}
+		}]
+	}`)
	var res RecommendationsResponse
	if err := json.Unmarshal(body, &res); err != nil {
		t.Fatalf("unmarshal: %v", err)
	}
-	if res.Version != "v1" || len(res.Data) != 1 || res.Data[0].Person.FullName != "f" {
+	if res.Version != "v1" {
+		t.Fatalf("expected version v1, got %s", res.Version)
+	}
+	if len(res.Data) != 1 {
+		t.Fatalf("expected 1 data item, got %d", len(res.Data))
+	}
+	if res.Data[0].Person.FullName != "John Doe" {
+		t.Fatalf("expected full name 'John Doe', got %s", res.Data[0].Person.FullName)
+	}
+	if res.Data[0].UUID != "test-uuid" {
+		t.Fatalf("expected uuid 'test-uuid', got %s", res.Data[0].UUID)
+	}
-		t.Fatalf("unexpected response: %+v", res)
-	}
}
handler/payload/projects_test.go (1)

8-17: Apply the same readability improvements as other payload tests.

This test has the same readability issues as other payload tests in the codebase. The long JSON string and single-character test values make it hard to verify correct field mapping.

func TestProjectsResponseJSON(t *testing.T) {
-	body := []byte(`{"version":"v1","data":[{"uuid":"u","language":"l","title":"t","excerpt":"e","url":"u","icon":"i","is_open_source":true,"created_at":"c","updated_at":"up"}]}`)
+	body := []byte(`{
+		"version":"v1",
+		"data":[{
+			"uuid":"project-uuid",
+			"language":"Go",
+			"title":"Test Project",
+			"excerpt":"A test project",
+			"url":"https://github.com/test/project",
+			"icon":"project-icon",
+			"is_open_source":true,
+			"created_at":"2023-01-01",
+			"updated_at":"2023-01-02"
+		}]
+	}`)
	var res ProjectsResponse
	if err := json.Unmarshal(body, &res); err != nil {
		t.Fatalf("unmarshal: %v", err)
	}
-	if res.Version != "v1" || len(res.Data) != 1 || !res.Data[0].IsOpenSource {
+	if res.Version != "v1" {
+		t.Fatalf("expected version v1, got %s", res.Version)
+	}
+	if len(res.Data) != 1 {
+		t.Fatalf("expected 1 data item, got %d", len(res.Data))
+	}
+	if !res.Data[0].IsOpenSource {
+		t.Fatalf("expected IsOpenSource to be true")
+	}
-		t.Fatalf("unexpected response: %+v", res)
-	}
}
handler/payload/experience_test.go (1)

8-17: Consistent with other payload tests but needs readability improvements.

This test follows the same pattern as other payload tests in the codebase, which is good for consistency. However, it has the same readability issues with the long JSON string and single-character test values.

func TestExperienceResponseJSON(t *testing.T) {
-	body := []byte(`{"version":"v1","data":[{"uuid":"u","company":"c","employment_type":"e","location_type":"l","position":"p","start_date":"sd","end_date":"ed","summary":"s","country":"co","city":"ci","skills":"sk"}]}`)
+	body := []byte(`{
+		"version":"v1",
+		"data":[{
+			"uuid":"exp-uuid",
+			"company":"Tech Corp",
+			"employment_type":"full-time",
+			"location_type":"remote",
+			"position":"Software Engineer",
+			"start_date":"2020-01-01",
+			"end_date":"2023-01-01",
+			"summary":"Worked on backend systems",
+			"country":"USA",
+			"city":"San Francisco",
+			"skills":"Go, PostgreSQL"
+		}]
+	}`)
	var res ExperienceResponse
	if err := json.Unmarshal(body, &res); err != nil {
		t.Fatalf("unmarshal: %v", err)
	}
-	if res.Version != "v1" || len(res.Data) != 1 || res.Data[0].UUID != "u" {
+	if res.Version != "v1" {
+		t.Fatalf("expected version v1, got %s", res.Version)
+	}
+	if len(res.Data) != 1 {
+		t.Fatalf("expected 1 data item, got %d", len(res.Data))
+	}
+	if res.Data[0].UUID != "exp-uuid" {
+		t.Fatalf("expected uuid 'exp-uuid', got %s", res.Data[0].UUID)
+	}
-		t.Fatalf("unexpected response: %+v", res)
-	}
}
handler/projects_test.go (1)

11-55: Consider refactoring duplicated test logic.

This test follows the same pattern as talks_test.go with nearly identical code. Consider extracting a common test helper function to reduce duplication.

Example helper function:

func testFileHandler(t *testing.T, makeHandler func(string) interface{}, handlerMethod func(interface{}, http.ResponseWriter, *http.Request) error) {
    // Common test logic here
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9c7f77e and a5b183d.

📒 Files selected for processing (28)
  • go.mod (1 hunks)
  • handler/categories.go (2 hunks)
  • handler/categories_posts_test.go (0 hunks)
  • handler/categories_test.go (1 hunks)
  • handler/education_test.go (1 hunks)
  • handler/experience_test.go (1 hunks)
  • handler/file_handlers_more_test.go (0 hunks)
  • handler/payload/categories_test.go (0 hunks)
  • handler/payload/education_test.go (1 hunks)
  • handler/payload/experience_test.go (1 hunks)
  • handler/payload/posts_filters_test.go (1 hunks)
  • handler/payload/posts_response_test.go (0 hunks)
  • handler/payload/posts_slug_test.go (1 hunks)
  • handler/payload/profile_test.go (1 hunks)
  • handler/payload/projects_test.go (1 hunks)
  • handler/payload/recommendations_test.go (1 hunks)
  • handler/payload/social_test.go (1 hunks)
  • handler/payload/tags_test.go (1 hunks)
  • handler/payload/talks_test.go (1 hunks)
  • handler/payload/users_test.go (1 hunks)
  • handler/posts.go (2 hunks)
  • handler/posts_test.go (1 hunks)
  • handler/profile_test.go (2 hunks)
  • handler/projects_test.go (1 hunks)
  • handler/recommendations_test.go (1 hunks)
  • handler/social_test.go (1 hunks)
  • handler/talks_test.go (1 hunks)
  • handler/test_helpers_test.go (1 hunks)
💤 Files with no reviewable changes (4)
  • handler/payload/categories_test.go
  • handler/payload/posts_response_test.go
  • handler/categories_posts_test.go
  • handler/file_handlers_more_test.go
🧰 Additional context used
🧬 Code Graph Analysis (12)
handler/payload/education_test.go (1)
handler/payload/education.go (1)
  • EducationResponse (3-6)
handler/payload/talks_test.go (1)
handler/payload/talks.go (1)
  • TalksResponse (3-6)
handler/payload/posts_slug_test.go (1)
handler/payload/posts.go (1)
  • GetSlugFrom (47-51)
handler/payload/tags_test.go (2)
database/model.go (1)
  • Tag (107-119)
handler/payload/tags.go (1)
  • GetTagsResponse (12-25)
handler/recommendations_test.go (1)
handler/recommendations.go (1)
  • MakeRecommendationsHandler (15-19)
handler/payload/users_test.go (1)
handler/payload/users.go (1)
  • UserResponse (3-13)
handler/projects_test.go (1)
handler/projects.go (1)
  • MakeProjectsHandler (15-19)
handler/payload/experience_test.go (1)
handler/payload/experience.go (1)
  • ExperienceResponse (3-6)
handler/social_test.go (1)
handler/social.go (1)
  • MakeSocialHandler (15-19)
handler/talks_test.go (1)
handler/talks.go (1)
  • MakeTalksHandler (15-19)
handler/profile_test.go (1)
handler/profile.go (1)
  • MakeProfileHandler (15-19)
handler/posts.go (1)
database/repository/posts.go (1)
  • Posts (12-16)
🪛 GitHub Actions: Tests
handler/categories_test.go

[error] 74-74: Test failure due to invalid input syntax for type uuid: "u1" (SQLSTATE 22P02) when creating user.


[error] 97-97: TestCategoriesHandlerIndex_Success failed: create user error - invalid input syntax for type uuid: "u1" (SQLSTATE 22P02).

handler/posts_test.go

[error] 93-93: Test failure due to invalid input syntax for type uuid: "u1" (SQLSTATE 22P02) when creating user.


[error] 106-106: TestPostsHandlerIndex_Success failed: create user error - invalid input syntax for type uuid: "u1" (SQLSTATE 22P02).


[error] 93-93: Test failure due to invalid input syntax for type uuid: "u1" (SQLSTATE 22P02) when creating user.


[error] 129-129: TestPostsHandlerShow_Success failed: create user error - invalid input syntax for type uuid: "u1" (SQLSTATE 22P02).

🔇 Additional comments (16)
go.mod (1)

11-11: Approve Dependency Promotion: github.com/rs/cors v1.11.1

  • File: go.mod (line 11)
  • Dependency moved from indirect to direct use as expected.
  • v1.11.1 is the latest release (Aug 2025) and contains all fixes for prior CORS DoS issues—no known vulnerabilities.

No further changes needed.

handler/test_helpers_test.go (2)

9-12: Well-designed generic test envelope structure.

The testEnvelope struct provides a clean, reusable pattern for test data across multiple handler tests. The use of interface{} for the Data field appropriately balances flexibility with simplicity.


14-25: Excellent test helper implementation.

The writeJSON function is well-implemented with proper error handling and follows Go testing best practices by using t.Helper(). This utility effectively consolidates the temporary file creation pattern used across multiple test files.

The function correctly:

  • Marks itself as a test helper
  • Handles file creation and encoding errors appropriately
  • Closes the file before returning
  • Provides a clean interface for test data setup
handler/categories.go (2)

19-23: Constructor change aligns with architectural shift.

The constructor now accepts a concrete repository type instead of an interface, which is consistent with the PR objective of removing repository interfaces.


16-16: Repository abstraction removal validated – no remaining interfaces detected

All searches for repository interface definitions and mocking patterns returned no results. The codebase consistently uses the concrete *repository.Categories type across:

  • handler/categories.go (handler now holds *repository.Categories)
  • boost/router.go (router constructs &repository.Categories{DB:…})
  • cli/posts/factory.go (factory passes &repository.Categories{DB:…})
  • handler/categories_test.go (integration tests using real *repository.Categories)
  • repository tests (direct instantiation of repository.Categories)

Testability is preserved via integration tests against a real Postgres container. No further action required.

handler/recommendations_test.go (1)

11-55: Comprehensive handler test with good coverage.

This test provides excellent coverage of the RecommendationsHandler functionality:

  • ✅ Tests successful JSON response handling
  • ✅ Verifies HTTP status codes and response decoding
  • ✅ Tests conditional requests with ETag support (If-None-Match header)
  • ✅ Tests error handling with malformed JSON
  • ✅ Proper cleanup of temporary files
  • ✅ Uses shared test helpers for consistency

The test structure aligns well with the PR's shift from interface-based mocking to integration-style testing.

handler/experience_test.go (1)

11-81: Excellent test coverage for ExperienceHandler.

The test suite comprehensively covers all critical scenarios including successful responses, ETag-based caching (304 Not Modified), error handling with malformed JSON, and payload validation. The tests follow a consistent pattern with other handler test files and properly use the shared test helpers.

handler/education_test.go (1)

11-81: Well-structured test suite following established patterns.

The test implementation is consistent with other handler test files and provides comprehensive coverage of all critical scenarios including successful responses, ETag-based caching, error handling, and payload validation.

handler/profile_test.go (1)

12-77: Good refactoring to use shared test helpers.

The test has been successfully updated to use the unified testEnvelope and writeJSON helpers, improving consistency across the codebase. The test coverage remains comprehensive and the payload validation correctly handles the map structure expected for profile data.

handler/social_test.go (1)

11-81: Consistent test implementation for SocialHandler.

The test suite follows the established pattern and provides comprehensive coverage of all critical scenarios. The payload validation correctly handles the array data structure expected for social data, maintaining consistency with similar handlers.

handler/categories_test.go (1)

21-94: Well-structured integration test setup.

The test helper function properly sets up a PostgreSQL container, handles cleanup, runs migrations, and seeds test data. Good use of t.Helper() and proper error handling throughout.

handler/posts_test.go (2)

22-38: Good unit test coverage for error cases.

Proper testing of parse errors and missing parameters with appropriate error assertions.


40-103: Well-implemented integration test helper.

Good separation of concerns with a dedicated helper function for repository setup, proper cleanup, and comprehensive migration setup.

handler/talks_test.go (2)

11-55: Comprehensive test coverage for file-based handler.

Excellent test structure covering:

  • Successful JSON response handling
  • ETag-based conditional requests (304 Not Modified)
  • Error handling for malformed JSON files

The test properly validates both HTTP status codes and response payload structure.


57-81: Good payload validation test.

Proper verification of response data structure with type assertions and content validation.

handler/projects_test.go (1)

57-81: Good payload validation with consistent structure.

The payload validation follows the same reliable pattern as other file-based handler tests.

@gocanto gocanto added testing and removed testing labels Aug 6, 2025
@gocanto gocanto changed the title refactor: remove repo interfaces refactor: Remove useless interfaces + tests improvements Aug 6, 2025
@gocanto gocanto marked this pull request as ready for review August 6, 2025 04:05
@gocanto
Copy link
Collaborator Author

gocanto commented Aug 6, 2025

@coderabbitai full review

@coderabbitai
Copy link

coderabbitai bot commented Aug 6, 2025

✅ Actions performed

Full review triggered.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (1)
handler/posts.go (1)

16-22: Consider using type aliases for improved readability.

The refactoring from interface to concrete type is correct and aligns with the PR objectives. However, the previous suggestion about type aliases for function signatures remains relevant for better readability:

type GetAllPostsFunc func(queries.PostFilters, pagination.Paginate) (*pagination.Pagination[database.Post], error)
type FindPostByFunc func(slug string) *database.Post

type PostsHandler struct {
	GetAll GetAllPostsFunc
	FindBy FindPostByFunc
}

func MakePostsHandler(getAll GetAllPostsFunc, findBy FindPostByFunc) PostsHandler {
	return PostsHandler{GetAll: getAll, FindBy: findBy}
}
🧹 Nitpick comments (10)
handler/payload/posts_slug_test.go (1)

8-14: Consider expanding test coverage and improving error messages.

The test correctly validates slug normalization but could benefit from additional test cases and better error reporting.

Consider this enhanced version with multiple test cases:

 func TestGetSlugFrom(t *testing.T) {
-	r := httptest.NewRequest("GET", "/posts/s", nil)
-	r.SetPathValue("slug", "  SLUG ")
-	if s := GetSlugFrom(r); s != "slug" {
-		t.Fatalf("slug %s", s)
-	}
+	tests := []struct {
+		name     string
+		input    string
+		expected string
+	}{
+		{"whitespace and uppercase", "  SLUG ", "slug"},
+		{"already normalized", "slug", "slug"},
+		{"empty string", "", ""},
+		{"mixed case", "My-Post-Title", "my-post-title"},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			r := httptest.NewRequest("GET", "/posts/s", nil)
+			r.SetPathValue("slug", tt.input)
+			if got := GetSlugFrom(r); got != tt.expected {
+				t.Errorf("GetSlugFrom() = %q, want %q", got, tt.expected)
+			}
+		})
+	}
 }
handler/payload/users_test.go (1)

8-17: Enhance test coverage and readability.

The test correctly validates JSON unmarshalling but only checks 3 out of 9 fields in the UserResponse struct.

Consider improving test coverage and readability:

 func TestUserResponseJSON(t *testing.T) {
-	body := []byte(`{"uuid":"u","first_name":"f","last_name":"l","username":"un","display_name":"dn","bio":"b","picture_file_name":"p","profile_picture_url":"pu","is_admin":true}`)
+	body := []byte(`{
+		"uuid":"test-uuid",
+		"first_name":"John",
+		"last_name":"Doe", 
+		"username":"johndoe",
+		"display_name":"John Doe",
+		"bio":"Test bio",
+		"picture_file_name":"profile.jpg",
+		"profile_picture_url":"https://example.com/profile.jpg",
+		"is_admin":true
+	}`)
+	
 	var res UserResponse
 	if err := json.Unmarshal(body, &res); err != nil {
 		t.Fatalf("unmarshal: %v", err)
 	}
-	if res.UUID != "u" || res.FirstName != "f" || !res.IsAdmin {
-		t.Fatalf("unexpected response: %+v", res)
-	}
+	
+	// Validate all key fields
+	if res.UUID != "test-uuid" {
+		t.Errorf("UUID = %q, want %q", res.UUID, "test-uuid")
+	}
+	if res.FirstName != "John" {
+		t.Errorf("FirstName = %q, want %q", res.FirstName, "John")
+	}
+	if res.Username != "johndoe" {
+		t.Errorf("Username = %q, want %q", res.Username, "johndoe")
+	}
+	if !res.IsAdmin {
+		t.Error("IsAdmin should be true")
+	}
 }
handler/test_helpers_test.go (1)

14-25: Consider adding file cleanup for temporary files.

The helper function is well-implemented but temporary files are not cleaned up, which could accumulate during test runs.

Consider using t.Cleanup() to ensure temporary files are removed:

 func writeJSON(t *testing.T, v interface{}) string {
 	t.Helper()
 	f, err := os.CreateTemp("", "data.json")
 	if err != nil {
 		t.Fatalf("tmp: %v", err)
 	}
+	t.Cleanup(func() { os.Remove(f.Name()) })
+	
 	if err := json.NewEncoder(f).Encode(v); err != nil {
 		t.Fatalf("encode: %v", err)
 	}
 	f.Close()
 	return f.Name()
 }
handler/payload/social_test.go (1)

8-17: Consider expanding test scenarios.

The test correctly validates JSON unmarshalling but only covers a single scenario with one data element.

Consider testing additional scenarios:

 func TestSocialResponseJSON(t *testing.T) {
-	body := []byte(`{"version":"v1","data":[{"uuid":"u","handle":"h","url":"u","description":"d","name":"n"}]}`)
-	var res SocialResponse
-	if err := json.Unmarshal(body, &res); err != nil {
-		t.Fatalf("unmarshal: %v", err)
-	}
-	if res.Version != "v1" || len(res.Data) != 1 || res.Data[0].Name != "n" {
-		t.Fatalf("unexpected response: %+v", res)
-	}
+	tests := []struct {
+		name     string
+		json     string
+		wantLen  int
+		wantVer  string
+	}{
+		{
+			name:    "single item",
+			json:    `{"version":"v1","data":[{"uuid":"u","handle":"h","url":"u","description":"d","name":"twitter"}]}`,
+			wantLen: 1,
+			wantVer: "v1",
+		},
+		{
+			name:    "empty data",
+			json:    `{"version":"v2","data":[]}`,
+			wantLen: 0,
+			wantVer: "v2",
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			var res SocialResponse
+			if err := json.Unmarshal([]byte(tt.json), &res); err != nil {
+				t.Fatalf("unmarshal: %v", err)
+			}
+			if res.Version != tt.wantVer || len(res.Data) != tt.wantLen {
+				t.Errorf("got version=%q len=%d, want version=%q len=%d", 
+					res.Version, len(res.Data), tt.wantVer, tt.wantLen)
+			}
+		})
+	}
 }
handler/payload/talks_test.go (1)

8-17: LGTM! Well-structured JSON unmarshalling test.

The test correctly validates JSON unmarshalling into the TalksResponse struct and follows Go testing conventions with appropriate error handling.

Consider validating additional fields from the first data element to ensure complete unmarshalling accuracy:

-	if res.Version != "v1" || len(res.Data) != 1 || res.Data[0].Title != "t" {
+	if res.Version != "v1" || len(res.Data) != 1 || res.Data[0].Title != "t" || res.Data[0].UUID != "u" || res.Data[0].Subject != "s" {
		t.Fatalf("unexpected response: %+v", res)
	}
handler/payload/tags_test.go (1)

9-15: LGTM! Effective function transformation test.

The test correctly validates the GetTagsResponse function's ability to transform database.Tag entities into TagResponse payloads.

Consider validating additional mapped fields for more comprehensive coverage:

-	if len(r) != 1 || r[0].Slug != "s" {
+	if len(r) != 1 || r[0].Slug != "s" || r[0].UUID != "1" || r[0].Name != "n" || r[0].Description != "d" {
		t.Fatalf("unexpected %#v", r)
	}
handler/categories.go (1)

16-16: Refactoring from interface to concrete type reduces abstraction.

The change from an interface to *repository.Categories concrete type reduces the abstraction layer. While this simplifies dependency management, it also reduces testability and flexibility compared to interface-based injection.

Consider the trade-offs:

  • Pros: Simpler dependency management, no need for interface definitions
  • Cons: Reduced testability (harder to mock), tighter coupling, less flexibility for different implementations

If testing is a concern, you might want to keep the interface or use dependency injection patterns.

handler/talks_test.go (1)

11-81: Consider test helper functions to reduce duplication.

While the test coverage is excellent, there's significant duplication across similar handler test files (education, talks, social, etc.). Consider creating shared test helper functions to reduce code repetition.

For example, you could create a generic handler test function:

func testFileHandlerBehavior(t *testing.T, makeHandler func(string) interface{}, handlerMethod string, endpoint string) {
    // Common test logic here
}
handler/posts_test.go (1)

41-104: Extract common testcontainer setup to reduce duplication.

The makePostsRepo helper is well-implemented with proper Docker detection, cleanup, and database seeding. However, this setup is very similar to makeCategoriesRepo in categories_test.go.

Consider extracting the common testcontainer setup into a shared helper function:

// In a shared test helper file
func makeTestDB(t *testing.T) *database.Connection {
    // Common setup code for testcontainer, connection, migrations
    return conn
}

func makePostsRepo(t *testing.T) *repository.Posts {
    conn := makeTestDB(t)
    // Posts-specific seeding
    return &repository.Posts{DB: conn}
}
handler/categories_test.go (1)

97-118: Consider expanding test coverage.

The single success test is good but minimal. Consider adding tests for error scenarios similar to the comprehensive coverage in posts_test.go:

  • JSON parsing errors
  • Database connection failures
  • Empty result sets
  • Pagination edge cases
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9c7f77e and 38a1635.

📒 Files selected for processing (28)
  • go.mod (1 hunks)
  • handler/categories.go (2 hunks)
  • handler/categories_posts_test.go (0 hunks)
  • handler/categories_test.go (1 hunks)
  • handler/education_test.go (1 hunks)
  • handler/experience_test.go (1 hunks)
  • handler/file_handlers_more_test.go (0 hunks)
  • handler/payload/categories_test.go (0 hunks)
  • handler/payload/education_test.go (1 hunks)
  • handler/payload/experience_test.go (1 hunks)
  • handler/payload/posts_filters_test.go (1 hunks)
  • handler/payload/posts_response_test.go (0 hunks)
  • handler/payload/posts_slug_test.go (1 hunks)
  • handler/payload/profile_test.go (1 hunks)
  • handler/payload/projects_test.go (1 hunks)
  • handler/payload/recommendations_test.go (1 hunks)
  • handler/payload/social_test.go (1 hunks)
  • handler/payload/tags_test.go (1 hunks)
  • handler/payload/talks_test.go (1 hunks)
  • handler/payload/users_test.go (1 hunks)
  • handler/posts.go (2 hunks)
  • handler/posts_test.go (1 hunks)
  • handler/profile_test.go (2 hunks)
  • handler/projects_test.go (1 hunks)
  • handler/recommendations_test.go (1 hunks)
  • handler/social_test.go (1 hunks)
  • handler/talks_test.go (1 hunks)
  • handler/test_helpers_test.go (1 hunks)
💤 Files with no reviewable changes (4)
  • handler/payload/posts_response_test.go
  • handler/payload/categories_test.go
  • handler/file_handlers_more_test.go
  • handler/categories_posts_test.go
🧰 Additional context used
🧬 Code Graph Analysis (20)
handler/payload/education_test.go (1)
handler/payload/education.go (1)
  • EducationResponse (3-6)
handler/payload/social_test.go (1)
handler/payload/social.go (1)
  • SocialResponse (3-6)
handler/payload/posts_slug_test.go (1)
handler/payload/posts.go (1)
  • GetSlugFrom (47-51)
handler/payload/profile_test.go (1)
handler/payload/profile.go (1)
  • ProfileResponse (3-6)
handler/recommendations_test.go (1)
handler/recommendations.go (1)
  • MakeRecommendationsHandler (15-19)
handler/categories.go (1)
database/repository/categories.go (1)
  • Categories (12-14)
handler/categories_test.go (8)
database/repository/categories.go (1)
  • Categories (12-14)
env/env.go (1)
  • Environment (9-15)
env/db.go (1)
  • DBEnvironment (5-14)
database/model.go (4)
  • DriverName (9-9)
  • User (37-61)
  • Category (86-98)
  • PostCategory (100-105)
database/connection.go (1)
  • MakeConnection (19-32)
handler/categories.go (1)
  • MakeCategoriesHandler (19-23)
database/repository/pagination/pagination.go (1)
  • Pagination (14-22)
handler/payload/categories.go (1)
  • CategoryResponse (5-10)
handler/payload/talks_test.go (1)
handler/payload/talks.go (1)
  • TalksResponse (3-6)
handler/experience_test.go (1)
handler/experience.go (1)
  • MakeExperienceHandler (15-19)
handler/education_test.go (1)
handler/education.go (1)
  • MakeEducationHandler (15-19)
handler/payload/recommendations_test.go (1)
handler/payload/recommendations.go (1)
  • RecommendationsResponse (3-6)
handler/payload/experience_test.go (1)
handler/payload/experience.go (1)
  • ExperienceResponse (3-6)
handler/profile_test.go (1)
handler/profile.go (1)
  • MakeProfileHandler (15-19)
handler/talks_test.go (1)
handler/talks.go (1)
  • MakeTalksHandler (15-19)
handler/projects_test.go (1)
handler/projects.go (1)
  • MakeProjectsHandler (15-19)
handler/posts.go (1)
database/repository/posts.go (1)
  • Posts (12-16)
handler/social_test.go (1)
handler/social.go (1)
  • MakeSocialHandler (15-19)
handler/payload/tags_test.go (2)
database/model.go (1)
  • Tag (107-119)
handler/payload/tags.go (1)
  • GetTagsResponse (12-25)
handler/payload/users_test.go (1)
handler/payload/users.go (1)
  • UserResponse (3-13)
handler/payload/projects_test.go (1)
handler/payload/projects.go (1)
  • ProjectsResponse (3-6)
🔇 Additional comments (29)
handler/test_helpers_test.go (1)

9-12: LGTM: Well-structured test envelope.

The testEnvelope struct appropriately models a versioned data container with proper JSON tags.

handler/payload/education_test.go (1)

8-17: LGTM! Consistent JSON unmarshalling test pattern.

The test follows the established pattern for payload tests and effectively validates JSON unmarshalling into the EducationResponse struct. Good consistency with other payload tests in the codebase.

handler/payload/profile_test.go (1)

8-17: LGTM! Excellent handling of nested structure validation.

The test effectively validates JSON unmarshalling for the complex nested ProfileResponse structure, including validation of nested Skills slice elements. Well-structured approach for testing multi-level data structures.

handler/payload/posts_filters_test.go (1)

5-11: LGTM! Comprehensive mapping function validation.

The test thoroughly validates the GetPostsFiltersFrom function by testing all filter field mappings in a single, efficient assertion. Excellent coverage of the mapping functionality.

handler/payload/recommendations_test.go (1)

8-17: LGTM! Well-structured JSON unmarshalling test.

The test correctly validates the core structure of RecommendationsResponse including version, data array length, and nested person fields. The use of minimal field values is appropriate for unit testing focused on structural validation.

handler/payload/experience_test.go (1)

8-17: LGTM! Comprehensive JSON unmarshalling test.

The test thoroughly validates the ExperienceResponse structure with a comprehensive JSON payload containing all relevant fields. The assertions appropriately check version, data array length, and specific field access.

handler/recommendations_test.go (1)

11-55: LGTM! Comprehensive HTTP handler test with proper coverage.

The test effectively covers the main scenarios:

  • Successful JSON response handling
  • Conditional requests with ETag support (If-None-Match header)
  • Error handling with malformed JSON files

The use of temporary files with proper cleanup and httptest for HTTP testing follows Go best practices.

handler/payload/projects_test.go (1)

8-17: LGTM! Consistent and well-structured payload test.

The test follows the established pattern for payload validation and includes good coverage of different field types, particularly the boolean IsOpenSource field. The comprehensive JSON structure appropriately tests all project-related fields.

handler/experience_test.go (2)

11-55: LGTM! Comprehensive handler test following established patterns.

The test covers all essential scenarios including successful responses, conditional requests with ETag support, and error handling. The implementation is consistent with other handler tests in the codebase.


57-81: Excellent addition of payload structure validation.

This additional test function provides valuable validation of the response payload structure through type assertions. It ensures the handler returns the expected data format with proper UUID field access, complementing the basic handler functionality test.

handler/categories.go (2)

6-6: Import addition aligns with concrete type usage.

The addition of the repository import is necessary for using the concrete *repository.Categories type instead of the interface.


19-23: Constructor updated consistently with struct changes.

The constructor function correctly accepts and assigns the concrete *repository.Categories type, maintaining consistency with the struct field change.

handler/education_test.go (2)

11-55: Comprehensive test coverage for HTTP handler behavior.

The test covers the essential scenarios:

  • Successful JSON serving with HTTP 200
  • ETag-based conditional requests returning HTTP 304
  • Error handling for malformed JSON files

The test structure is well-organized and follows good practices with proper cleanup using defer os.Remove().


57-81: Effective payload structure validation.

This test ensures the response data structure is correct by:

  • Decoding the JSON response into a testEnvelope
  • Validating the data is an array with expected structure
  • Verifying the UUID field in the payload

The type assertions with proper error handling make the test robust.

handler/talks_test.go (2)

11-55: Consistent and thorough test coverage.

The test follows the same comprehensive pattern as other handler tests, covering:

  • Successful response handling
  • ETag-based caching with If-None-Match header
  • Error handling for malformed JSON

This consistency across handler tests is beneficial for maintainability.


57-81: Proper payload validation with type safety.

The payload validation correctly verifies the JSON structure and ensures the expected UUID field is present in the talks data.

handler/social_test.go (2)

11-55: Comprehensive test coverage following established pattern.

The test properly validates all essential handler behaviors including HTTP responses, ETag handling, and error scenarios. The consistency with other handler tests maintains good testing standards.


57-81: Effective payload structure validation.

The payload test correctly verifies the JSON structure and UUID field presence, ensuring data integrity.

handler/profile_test.go (4)

12-12: Improved test data consistency with shared helpers.

The refactoring to use testEnvelope and writeJSON helper improves consistency across test files and reduces duplication.

Also applies to: 58-58


26-32: Enhanced response validation with JSON decoding.

The addition of explicit JSON response decoding and version validation makes the test more robust compared to just checking HTTP status codes.


57-57: Corrected test naming and handler usage.

The test name and handler function calls have been properly corrected to use ProfileHandler consistently, fixing what appears to have been copy-paste errors.

Also applies to: 61-62


69-76: Proper payload validation with type safety.

The payload validation now correctly decodes the JSON response and validates the expected map structure with the "nickname" field, ensuring data integrity.

handler/posts.go (1)

6-6: Import change aligns with concrete repository usage.

The import update from github.com/oullin/database to github.com/oullin/database/repository correctly reflects the shift to using concrete repository types.

handler/posts_test.go (3)

23-39: Comprehensive error handling tests.

Good coverage of error scenarios with parse errors and missing parameters. The tests correctly verify that error conditions are properly handled.


93-98: UUID format issue resolved.

The use of uuid.NewString() correctly generates valid UUID formats, addressing the previous review comments about invalid UUID strings like "u1" and "p1".


106-151: Excellent integration test coverage.

The tests provide comprehensive coverage of both success and failure scenarios, with proper HTTP status code validation and JSON response verification. The use of real database integration instead of mocks provides better test reliability.

handler/categories_test.go (1)

74-84: UUID format issues resolved.

The use of uuid.NewString() for user, post, and category creation correctly generates valid UUID formats, addressing the previous review comments about invalid hardcoded UUIDs.

handler/projects_test.go (2)

11-55: Comprehensive file-based handler testing.

Excellent test coverage including:

  • Successful GET requests with proper JSON response
  • Conditional requests with If-None-Match header (ETag support)
  • Error handling for malformed JSON files
  • Proper cleanup of temporary files

The testing strategy is well-suited for file-based handlers.


57-81: Thorough payload validation.

Good addition of payload structure validation, ensuring the JSON response contains the expected data format and UUID fields. The type assertions provide robust verification of the response structure.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (4)
handler/tests/helpers.go (1)

14-25: Good test helper implementation with minor improvement opportunity.

The WriteJSON function is well-implemented with proper error handling and correct use of t.Helper(). The file closure and cleanup responsibility delegation to the caller is appropriate.

Consider explicitly handling the f.Close() error for completeness:

-	f.Close()
+	if err := f.Close(); err != nil {
+		t.Fatalf("close: %v", err)
+	}
handler/tests/helpers_test.go (1)

8-14: Basic test coverage with room for enhancement.

The test verifies the core functionality of WriteJSON but could be more comprehensive.

Consider adding validation of the actual file contents:

 func TestWriteJSON(t *testing.T) {
 	file := WriteJSON(t, TestEnvelope{Version: "v1"})
 	if file == "" {
 		t.Fatalf("expected file path")
 	}
+	
+	// Verify file contents
+	data, err := os.ReadFile(file)
+	if err != nil {
+		t.Fatalf("read file: %v", err)
+	}
+	var envelope TestEnvelope
+	if err := json.Unmarshal(data, &envelope); err != nil {
+		t.Fatalf("unmarshal: %v", err)
+	}
+	if envelope.Version != "v1" {
+		t.Fatalf("expected version v1, got %s", envelope.Version)
+	}
+	
 	os.Remove(file)
 }
handler/projects_test.go (2)

59-83: Good payload validation with opportunity for refactoring.

The payload validation test is thorough but could benefit from more robust type assertions and error messages.

Consider improving the type assertions:

 	arr, ok := resp.Data.([]interface{})
-	if !ok || len(arr) != 1 {
-		t.Fatalf("unexpected data: %+v", resp.Data)
+	if !ok {
+		t.Fatalf("expected array, got %T: %+v", resp.Data, resp.Data)
+	}
+	if len(arr) != 1 {
+		t.Fatalf("expected 1 element, got %d: %+v", len(arr), resp.Data)
 	}
 	m, ok := arr[0].(map[string]interface{})
-	if !ok || m["uuid"] != "1" {
-		t.Fatalf("unexpected payload: %+v", resp.Data)
+	if !ok {
+		t.Fatalf("expected map, got %T: %+v", arr[0], arr[0])
+	}
+	if m["uuid"] != "1" {
+		t.Fatalf("expected uuid=1, got %v", m["uuid"])
 	}

14-14: Consider reducing test data duplication.

Both tests use identical test data setup. Consider extracting this into a helper function or using table-driven tests to reduce duplication and improve maintainability.

func createTestProjectsData() tests.TestEnvelope {
	return tests.TestEnvelope{
		Version: "v1", 
		Data: []map[string]string{{"uuid": "1"}},
	}
}

Also applies to: 60-60

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 38a1635 and 8370b5a.

📒 Files selected for processing (9)
  • handler/education_test.go (1 hunks)
  • handler/experience_test.go (1 hunks)
  • handler/profile_test.go (2 hunks)
  • handler/projects_test.go (1 hunks)
  • handler/recommendations_test.go (1 hunks)
  • handler/social_test.go (1 hunks)
  • handler/talks_test.go (1 hunks)
  • handler/tests/helpers.go (1 hunks)
  • handler/tests/helpers_test.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • handler/talks_test.go
  • handler/social_test.go
  • handler/profile_test.go
  • handler/experience_test.go
  • handler/recommendations_test.go
  • handler/education_test.go
🔇 Additional comments (2)
handler/tests/helpers.go (1)

9-12: LGTM! Well-designed test envelope structure.

The TestEnvelope struct provides a clean, versioned wrapper for test data. The use of interface{} for the Data field offers the flexibility needed for various test scenarios.

handler/projects_test.go (1)

13-57: Comprehensive test coverage with good structure.

This test effectively covers the main scenarios for ProjectsHandler:

  • Successful JSON response handling
  • Conditional requests with If-None-Match
  • Error handling for malformed JSON

The test structure is clear and follows good Go testing practices.

@gocanto gocanto marked this pull request as draft August 6, 2025 05:19
@gocanto gocanto marked this pull request as ready for review August 6, 2025 05:37
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
handler/file_handler_test.go (1)

71-87: Consider more flexible assertion helpers.

While the assertion helpers work for specific test cases, they are quite rigid and may not scale well if the data structures change or if more complex assertions are needed.

Consider creating more flexible assertion helpers or using a testing library like testify/assert:

func assertArrayWithUUID(t *testing.T, expectedUUID string) func(*testing.T, any) {
    return func(t *testing.T, data any) {
        arr, ok := data.([]interface{})
        if !ok || len(arr) != 1 {
            t.Fatalf("expected single-item array, got: %+v", data)
        }
        m, ok := arr[0].(map[string]interface{})
        if !ok || m["uuid"] != expectedUUID {
            t.Fatalf("expected uuid=%s, got: %+v", expectedUUID, data)
        }
    }
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 31fdd3a and 097210a.

📒 Files selected for processing (11)
  • handler/categories_test.go (1 hunks)
  • handler/education_test.go (1 hunks)
  • handler/experience_test.go (1 hunks)
  • handler/file_handler_test.go (1 hunks)
  • handler/posts_test.go (1 hunks)
  • handler/profile_test.go (1 hunks)
  • handler/projects_test.go (1 hunks)
  • handler/recommendations_test.go (1 hunks)
  • handler/social_test.go (1 hunks)
  • handler/talks_test.go (1 hunks)
  • handler/tests/db.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (9)
  • handler/talks_test.go
  • handler/projects_test.go
  • handler/education_test.go
  • handler/experience_test.go
  • handler/categories_test.go
  • handler/profile_test.go
  • handler/posts_test.go
  • handler/recommendations_test.go
  • handler/social_test.go
🔇 Additional comments (12)
handler/tests/db.go (6)

1-13: LGTM! Clean package structure and imports.

The package structure is well-organized with a dedicated handlertests package for test utilities. The imports are appropriate for the functionality provided.


15-22: Good Docker availability check.

The Docker availability check using exec.LookPath is a good practice that provides clear feedback when Docker is not installed, allowing tests to be skipped gracefully rather than failing unexpectedly.


24-35: Solid container setup with proper cleanup.

The PostgreSQL container setup is well-configured with appropriate image selection (alpine for smaller size), proper credentials, and most importantly, cleanup registration using t.Cleanup() to ensure containers are terminated after tests.


46-63: Clean environment configuration and connection setup.

The environment setup correctly maps container details to the database environment structure, and the connection cleanup is properly registered. The error handling is appropriate for test setup.


65-67: No changes needed: migration order is correct

The models are already ordered so that parent tables (User → Post → Category → Tag) are created before their join tables (PostCategory, PostTag), and GORM will apply the foreign‐key constraints as expected. Everything looks in order.


37-44: Verify container wait strategy ensures port mapping readiness

I couldn’t locate the implementation of postgres.BasicWaitStrategies() in the codebase, so it’s unclear whether it waits for the mapped port before you call pg.Host()/pg.MappedPort(). Please double-check that your wait strategy covers container readiness (including port availability) to avoid intermittent failures when retrieving host or port.

Key call sites to verify:

  • handler/tests/db.go
  • database/connection_test.go
  • database/repository/repository_test.go
  • database/seeder/seeds/seeder_test.go
  • cli/clitest/helpers.go

If BasicWaitStrategies does not cover port readiness, consider adding a Wait.ForListeningPort("5432/tcp") or a retry loop around the port lookup.

handler/file_handler_test.go (6)

1-12: Clean imports and package structure.

The imports are well-organized, appropriately aliasing baseHttp and pkgHttp to avoid conflicts. The package structure follows Go conventions.


14-23: Well-designed test framework structure.

The fileHandler interface and fileHandlerTestCase struct provide a clean abstraction for testing file-based handlers. The use of factory functions allows for flexible handler creation while maintaining type safety.


25-37: Comprehensive HTTP handler testing setup.

The test setup creates temporary files, makes HTTP requests, and validates responses properly. The cleanup with defer os.Remove(file) ensures no test artifacts are left behind.


39-46: Good response validation logic.

The response decoding and validation checks both the HTTP status and the expected data structure, including version verification. This ensures the API contract is properly maintained.


48-56: Excellent caching behavior testing.

Testing the If-None-Match header with ETag functionality is crucial for HTTP caching. The test correctly expects a 304 Not Modified status, validating proper caching implementation.


58-69: Thorough error handling validation.

The malformed JSON test is essential for verifying error handling. Creating a file with invalid JSON ("{") and expecting an error ensures the handler properly validates input data.

@gocanto gocanto changed the title refactor: Remove useless interfaces + tests improvements [refactor] Remove useless interfaces + tests improvements Aug 6, 2025
@gocanto gocanto merged commit d3ec241 into main Aug 6, 2025
6 checks passed
@gocanto gocanto deleted the hk1dre-codex/remove-categoriesrepo-and-postsrepo-interfaces branch August 6, 2025 05:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants