File: IsolatedGfx_test.cpp

package info (click to toggle)
megacmd 2.5.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 32,592 kB
  • sloc: cpp: 326,437; ansic: 34,524; python: 4,630; java: 3,965; sh: 2,869; objc: 2,459; makefile: 197; xml: 113
file content (219 lines) | stat: -rw-r--r-- 8,231 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
#include "sdk_test_utils.h"
#include "SdkTest_test.h"

#include <memory>

namespace
{

using FIBITMAPPtr = std::unique_ptr<FIBITMAP, decltype(&FreeImage_Unload)>;

FIBITMAPPtr load(const fs::path& image, FREE_IMAGE_FORMAT fif)
{
#ifdef _WIN32
    return FIBITMAPPtr{FreeImage_LoadU(fif, image.c_str(), 0), &FreeImage_Unload};
#else
    return FIBITMAPPtr{FreeImage_Load(fif, image.c_str(), 0), &FreeImage_Unload};
#endif
}

bool isTransparency(const fs::path& image, FREE_IMAGE_FORMAT fif)
{
    if (const auto dib = load(image, fif); dib)
    {
        return FreeImage_IsTransparent(dib.get()) == TRUE;
    }
    else
    {
        LOG_err << "Failed to load image";
        return false;
    }
}

// Get meta data tag count. -1 if there are errors
int getMetadataCount(const fs::path& image, FREE_IMAGE_FORMAT fif)
{
    if (const auto dib = load(image, fif); dib)
    {
        return static_cast<int>(FreeImage_GetMetadataCount(FIMD_EXIF_MAIN, dib.get()));
    }
    else
    {
        LOG_err << "Failed to load image";
        return -1;
    }
};

}

class SdkTestIsolatedGfx : public SdkTest
{
protected:
    void SetUp() override;

    void TearDown() override;

    static constexpr const char* SOURCE = "test-data/gfx-processing-crash/SNC-2462__17D1439.tif";

    static constexpr const char* CRASH_IMAGE = "crash.tif";

    static constexpr const char* CRASH_THUMBNAIL = "crash_thumbnail.jpg";

    static constexpr const char* CRASH_PREVIEW = "crash_preview.jpg";

    static constexpr const char* INVALID_IMAGE = "invalid.jpg";

    static constexpr const char* INVALID_THUMBNAIL = "invalid_thumbnail.jpg";

    static constexpr const char* GOOD_IMAGE = "logo.png";

    static constexpr const char* GOOD_THUMBNAIL = "logo_thumbnail.png";

    static constexpr const char* GOOD_PREVIEW   = "logo_preview.png";

    static constexpr const char* TRANSPARENCY_IMAGE = "transparency.png";

    static constexpr const char* TRANSPARENCY_THUMBNAIL = "transparency_thumbnail.png";

    static constexpr const char* TRANSPARENCY_PREVIEW = "transparency_preview.jpg";

    static constexpr const char* ORIENTATION_IMAGE = "orientation.jpg";

    static constexpr const char* ORIENTATION_THUMBNAIL = "orientation_thumbnail.jpg";

    static constexpr const char* ORIENTATION_PREVIEW = "orientation_preview.jpg";
};

void SdkTestIsolatedGfx::SetUp()
{
    SdkTest::SetUp();

    ASSERT_NO_FATAL_FAILURE(getAccountsForTest(1));
}

void SdkTestIsolatedGfx::TearDown()
{
    SdkTest::TearDown();
}

/**
 * @brief GfxProcessingContinueSuccessfullyAfterCrash
 *          1. create thumbnail successfully
 *          2. create thumbnail and preview of a image which causes a gfx process crash.
 *          3. create preview still successfully after the crash
 *          4. create thumbnail of a not valid image expects false.
 *
 * @ Note:
 *          Basically a createThumbnail/createPreview might fail due to the following reason:
 *          
 *          1. The GFX process was already crashed (not running), therefore the error is 
 *             the pipe couldn't be connected
 *          2. The GFX process crashed while processing, therefore the error is others.
 *          
 *          For the 1st case, we'll retry so it is handled. For the 2nd case, we don't retry as
 *          we don't want to retry processing bad images which cause a crash. We have problems 
 *          here because gfxworker process uses multiple thread model.        
 *             When it is processing multiple GFX calls and crashes, we don't know which call is 
 *          processing bad images. So simply all calls are not retried.
 *             When the previous call results in a crash, the following immediate call may still
 *             connect to the pipe as the crash takes time to shutdown the whole process. Therefore
 *             the second call is dropped as well though it should be retried.
 *
 *          It has been discussed and we don't want to deal with these known problem at the moment
 *          as we want to start with simple. It happens rarely and the side effect is limited (thumbnail lost).
 *          We'll improve it when we find it is necessary.
 */
TEST_F(SdkTestIsolatedGfx, GfxProcessingContinueSuccessfullyAfterCrash)
{
    LOG_info << "___TEST GfxProcessingContinueSuccessfullyAfterCrash";

    MegaApi* api = megaApi[0].get();

    // 1. Create a thumbnail successfully
    ASSERT_TRUE(getFileFromArtifactory(std::string{"test-data/"} + GOOD_IMAGE, GOOD_IMAGE));
    ASSERT_TRUE(api->createThumbnail(GOOD_IMAGE, GOOD_THUMBNAIL)) << "create thumbnail should succeed";

    // 2. Create thumbnail and preview of a image which result in a crash
    // the image is selected by testing, thus not guaranteed. we'd either
    // find another media file or need another alternative if it couldn't
    // consistently result in a crash

    // Get the test media file
    fs::path destination{CRASH_IMAGE};
    ASSERT_TRUE(getFileFromArtifactory(SOURCE, destination));
    ASSERT_TRUE(fs::exists(destination));

    // Gfx process would crash due to the bad media file
    ASSERT_FALSE(api->createThumbnail(CRASH_IMAGE, CRASH_THUMBNAIL));
    ASSERT_FALSE(api->createPreview(CRASH_IMAGE, CRASH_PREVIEW));

    // Don't make a call too quickly. Workaround: see note in test case desription
    std::this_thread::sleep_for(std::chrono::milliseconds{200});

    // 3. Create a preview successfully
    ASSERT_TRUE(api->createPreview(GOOD_IMAGE, GOOD_PREVIEW)) << "create preview should succeed";

    // 4. Create thumbnail of a not valid image
    ASSERT_TRUE(getFileFromArtifactory(std::string{"test-data/"} + INVALID_IMAGE, INVALID_IMAGE));
    ASSERT_FALSE(api->createThumbnail(INVALID_IMAGE, INVALID_THUMBNAIL)) << "create invalid image's thumbnail should fail";

    LOG_info << "___TEST GfxProcessingContinueSuccessfullyAfterCrash end___";
}

TEST_F(SdkTestIsolatedGfx, ThumbnailSupportTransparency)
{
    LOG_info << "___TEST ThumbnailSupportTransparency";

    // Download test data
    ASSERT_TRUE(
        getFileFromArtifactory(std::string{"test-data/"} + TRANSPARENCY_IMAGE, TRANSPARENCY_IMAGE));

    // Thumbnail and preview
    MegaApi* api = megaApi[0].get();
    ASSERT_TRUE(api->createThumbnail(TRANSPARENCY_IMAGE, TRANSPARENCY_THUMBNAIL))
        << "create thumbnail should succeed";
    ASSERT_TRUE(api->createPreview(TRANSPARENCY_IMAGE, TRANSPARENCY_PREVIEW))
        << "create preview should succeed";

    // Use this to ensure FreeImage library is initialized for once
    [[maybe_unused]] const auto a =
        ::mega::makeUniqueFrom(MegaGfxProvider::createInternalInstance());

    // Check all are transparency images
    ASSERT_TRUE(isTransparency(fs::path{TRANSPARENCY_IMAGE}, FIF_PNG));
    ASSERT_EQ(FreeImage_GetFileType(TRANSPARENCY_THUMBNAIL, 0), FIF_PNG);
    ASSERT_TRUE(isTransparency(fs::path{TRANSPARENCY_THUMBNAIL}, FIF_PNG));
    ASSERT_EQ(FreeImage_GetFileType(TRANSPARENCY_PREVIEW, 0), FIF_JPEG);
    ASSERT_FALSE(isTransparency(fs::path{TRANSPARENCY_PREVIEW}, FIF_JPEG));

    LOG_info << "___TEST ThumbnailSupportTransparency end___";
}

TEST_F(SdkTestIsolatedGfx, MetaDataIsRemoved)
{
    LOG_info << "___TEST MetaDataIsRemoved";

    // Download test data
    ASSERT_TRUE(
        getFileFromArtifactory(std::string{"test-data/"} + ORIENTATION_IMAGE, ORIENTATION_IMAGE));

    // Thumbnail and preview
    MegaApi* api = megaApi[0].get();
    ASSERT_TRUE(api->createThumbnail(ORIENTATION_IMAGE, ORIENTATION_THUMBNAIL))
        << "create thumbnail should succeed";
    ASSERT_TRUE(api->createPreview(ORIENTATION_IMAGE, ORIENTATION_PREVIEW))
        << "create preview should succeed";

    // Use this to ensure FreeImage library is initialized for once
    [[maybe_unused]] const auto a =
        ::mega::makeUniqueFrom(MegaGfxProvider::createInternalInstance());

    // The original image has more than one EXIF data
    ASSERT_GT(getMetadataCount(fs::path{ORIENTATION_IMAGE}, FIF_JPEG), 1);

    // The thumbnail and preview has none EXIF data
    ASSERT_EQ(getMetadataCount(fs::path{ORIENTATION_PREVIEW}, FIF_JPEG), 0);
    ASSERT_EQ(getMetadataCount(fs::path{ORIENTATION_THUMBNAIL}, FIF_JPEG), 0);

    LOG_info << "___TEST MetaDataIsRemoved end___";
}