github.com/k0marov/go-socnet@v0.0.0-20220715154813-90d07867c782/features/posts/integration_test/posts_test.go (about)

     1  package posts_test
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"github.com/k0marov/go-socnet/core/general/core_values"
     8  	"github.com/k0marov/go-socnet/core/general/static_store"
     9  	helpers "github.com/k0marov/go-socnet/core/helpers/http_test_helpers"
    10  	. "github.com/k0marov/go-socnet/core/helpers/test_helpers"
    11  	"log"
    12  	"mime/multipart"
    13  	"net/http"
    14  	"net/http/httptest"
    15  	"os"
    16  	"path/filepath"
    17  	"strconv"
    18  	"testing"
    19  
    20  	"github.com/go-chi/chi/v5"
    21  	"github.com/k0marov/go-socnet/features/posts"
    22  	"github.com/k0marov/go-socnet/features/posts/delivery/http/responses"
    23  	"github.com/k0marov/go-socnet/features/posts/domain/values"
    24  	post_storage "github.com/k0marov/go-socnet/features/posts/store/file_storage"
    25  	"github.com/k0marov/go-socnet/features/profiles"
    26  	profile_entities "github.com/k0marov/go-socnet/features/profiles/domain/entities"
    27  	profile_models "github.com/k0marov/go-socnet/features/profiles/domain/models"
    28  	auth "github.com/k0marov/golang-auth"
    29  	_ "github.com/mattn/go-sqlite3"
    30  )
    31  
    32  func TestPosts(t *testing.T) {
    33  	// working directory
    34  	os.Mkdir("tmp_test", 0777)
    35  	os.Chdir("tmp_test")
    36  	defer func() {
    37  		os.Chdir("..")
    38  		os.RemoveAll("tmp_test")
    39  	}()
    40  
    41  	// db
    42  	sql := OpenSqliteDB(t)
    43  
    44  	r := chi.NewRouter()
    45  	// profiles
    46  	r.Route("/profiles", profiles.NewProfilesRouterImpl(sql))
    47  	fakeRegisterProfile := profiles.NewRegisterCallback(sql)
    48  	// posts
    49  	r.Route("/posts", posts.NewPostsRouterImpl(sql, profiles.NewProfileGetterImpl(sql)))
    50  
    51  	// helpers
    52  	createPost := func(t testing.TB, author auth.User, images [][]byte, text string) {
    53  		t.Helper()
    54  		body := bytes.NewBuffer(nil)
    55  		writer := multipart.NewWriter(body)
    56  
    57  		writer.WriteField("text", text)
    58  		for i, image := range images {
    59  			fw, _ := writer.CreateFormFile(fmt.Sprintf("image_%d", i+1), RandomString())
    60  			fw.Write(image)
    61  		}
    62  		writer.Close()
    63  		request := helpers.AddAuthDataToRequest(httptest.NewRequest(http.MethodPost, "/posts", body), author)
    64  		request.Header.Set("Content-Type", writer.FormDataContentType())
    65  
    66  		response := httptest.NewRecorder()
    67  		r.ServeHTTP(response, request)
    68  		AssertStatusCode(t, response, http.StatusOK)
    69  	}
    70  	getPosts := func(t testing.TB, author core_values.UserId, caller auth.User) []responses.PostResponse {
    71  		t.Helper()
    72  		request := helpers.AddAuthDataToRequest(httptest.NewRequest(http.MethodGet, "/posts/?profile_id="+author, nil), caller)
    73  		response := httptest.NewRecorder()
    74  		r.ServeHTTP(response, request)
    75  		AssertStatusCode(t, response, http.StatusOK)
    76  		var posts responses.PostsResponse
    77  		json.NewDecoder(response.Body).Decode(&posts)
    78  		return posts.Posts
    79  	}
    80  	assertImageCreated := func(t testing.TB, post responses.PostResponse, postImage responses.PostImageResponse, wantImage []byte) {
    81  		t.Helper()
    82  		path := filepath.Join(static_store.StaticDir, post_storage.GetPostDir(post.Id, post.Author.Id), post_storage.ImagePrefix+strconv.Itoa(postImage.Index))
    83  		got := readFile(t, path)
    84  		Assert(t, got, wantImage, "the stored image data")
    85  	}
    86  	deletePost := func(t testing.TB, postId values.PostId, author auth.User) {
    87  		t.Helper()
    88  		request := helpers.AddAuthDataToRequest(httptest.NewRequest(http.MethodDelete, "/posts/"+postId, nil), author)
    89  		response := httptest.NewRecorder()
    90  		r.ServeHTTP(response, request)
    91  		AssertStatusCode(t, response, http.StatusOK)
    92  	}
    93  	assertPostFilesDeleted := func(t testing.TB, postId values.PostId, author core_values.UserId) {
    94  		t.Helper()
    95  		postPath := filepath.Join(static_store.StaticDir, post_storage.GetPostDir(postId, author))
    96  		_, err := os.ReadDir(postPath)
    97  		AssertSomeError(t, err)
    98  	}
    99  	toggleLike := func(t testing.TB, postId values.PostId, caller auth.User) {
   100  		t.Helper()
   101  		request := helpers.AddAuthDataToRequest(httptest.NewRequest(http.MethodPost, "/posts/"+postId+"/toggle-like", nil), caller)
   102  		response := httptest.NewRecorder()
   103  		r.ServeHTTP(response, request)
   104  		AssertStatusCode(t, response, http.StatusOK)
   105  	}
   106  
   107  	registerProfile := func(user auth.User) profile_entities.Profile {
   108  		fakeRegisterProfile(user)
   109  		return profile_entities.Profile{
   110  			ProfileModel: profile_models.ProfileModel{
   111  				Id:       user.Id,
   112  				Username: user.Username,
   113  			},
   114  		}
   115  	}
   116  
   117  	// create 2 profiles
   118  	user1 := RandomAuthUser()
   119  	user2 := RandomAuthUser()
   120  	registerProfile(user1)
   121  	registerProfile(user2)
   122  
   123  	t.Run("creating, reading and deleting posts", func(t *testing.T) {
   124  
   125  		// create post (without images) belonging to 2-nd profile
   126  		text1 := "Hello, World!"
   127  		createPost(t, user2, [][]byte{}, text1)
   128  
   129  		// create post (with images) belonging to 2-nd profile
   130  		text2 := "Hello, World with Images!"
   131  		image1 := readFixture(t, "test_image.jpg")
   132  		image2 := readFixture(t, "test_image.jpg")
   133  		createPost(t, user2, [][]byte{image1, image2}, text2)
   134  
   135  		// assert they were created
   136  		posts := getPosts(t, user2.Id, user2)
   137  
   138  		AssertFatal(t, len(posts), 2, "number of created posts")
   139  
   140  		log.Print(fmt.Sprintf("first:  %+v, \nsecond: %+v", posts[0], posts[1]))
   141  
   142  		Assert(t, posts[0].Text, text1, "the first post's text")
   143  		Assert(t, posts[0].Author.Id, user2.Id, "first post's author")
   144  		AssertFatal(t, len(posts[0].Images), 0, "number of images in first post")
   145  
   146  		Assert(t, posts[1].Text, text2, "the second post's text")
   147  		Assert(t, posts[1].Author.Id, user2.Id, "second posts's author")
   148  		AssertFatal(t, len(posts[1].Images), 2, "number of images in second post")
   149  		assertImageCreated(t, posts[1], posts[1].Images[0], image1)
   150  		assertImageCreated(t, posts[1], posts[1].Images[1], image2)
   151  		// delete them
   152  		deletePost(t, posts[0].Id, user2)
   153  		deletePost(t, posts[1].Id, user2)
   154  		// assert they were deleted
   155  		nowPosts := getPosts(t, user2.Id, user2)
   156  		Assert(t, len(nowPosts), 0, "number of posts after deletion")
   157  		assertPostFilesDeleted(t, posts[0].Id, user2.Id)
   158  		assertPostFilesDeleted(t, posts[1].Id, user2.Id)
   159  	})
   160  	t.Run("liking posts", func(t *testing.T) {
   161  		// create a post belonging to 1-st profile
   162  		createPost(t, user1, [][]byte{}, "")
   163  		posts := getPosts(t, user1.Id, user1)
   164  
   165  		// like it from 2-nd profile
   166  		toggleLike(t, posts[0].Id, user2)
   167  		// assert it is liked
   168  		posts = getPosts(t, user1.Id, user2)
   169  		Assert(t, posts[0].IsLiked, true, "post is liked")
   170  
   171  		// unlike it from 2-nd profile
   172  		toggleLike(t, posts[0].Id, user2)
   173  		// assert it is not liked
   174  		posts = getPosts(t, user1.Id, user2)
   175  		Assert(t, posts[0].IsLiked, false, "post is not liked")
   176  	})
   177  }
   178  
   179  func readFixture(t testing.TB, filename string) []byte {
   180  	t.Helper()
   181  	return readFile(t, filepath.Join("..", "testdata", filename)) // ".." since we change the working directory to tmp_test
   182  }
   183  
   184  func readFile(t testing.TB, filepath string) []byte {
   185  	t.Helper()
   186  	data, err := os.ReadFile(filepath)
   187  	if err != nil {
   188  		t.Fatalf("error while reading file %s: %v", filepath, err)
   189  	}
   190  	return data
   191  }