<commit_before>%%%-------------------------------------------------------------------
%%% @author <NAME>
%%% @copyright (C) 2019 ACK CYFRONET AGH
%%% This software is released under the MIT license
%%% cited in 'LICENSE.txt'.
%%% @end
%%%-------------------------------------------------------------------
%%% @doc
%%% This file contains tests concerning the mechanisms of uploading and linking
%%% static GUI files of different services.
%%% @end
%%%-------------------------------------------------------------------
-module(gui_static_distribution_test_SUITE).
-author("<NAME>").

-include("http/rest.hrl").
-include("registered_names.hrl").
-include("datastore/oz_datastore_models.hrl").
-include_lib("ctool/include/onedata.hrl").
-include_lib("ctool/include/privileges.hrl").
-include_lib("ctool/include/errors.hrl").
-include_lib("ctool/include/http/headers.hrl").
-include_lib("ctool/include/test/test_utils.hrl").
-include_lib("ctool/include/test/assertions.hrl").
-include_lib("ctool/include/test/performance.hrl").

-include("api_test_utils.hrl").

%% API
-export([
    all/0,
    init_per_suite/1, end_per_suite/1,
    init_per_testcase/2, end_per_testcase/2
]).
-export([
    oz_worker_gui_is_set_up_after_startup/1,
    oz_panel_gui_setup_works/1,
    default_harvester_gui_is_automatically_linked/1,
    empty_gui_is_linked_after_provider_registration/1,
    op_worker_and_panel_gui_is_linked_upon_version_info_update/1,
    gui_is_unlinked_after_provider_deletion/1,
    gui_upload_requires_provider_auth/1,
    gui_upload_is_not_possible_for_onezone_services/1,
    gui_upload_for_inexistent_service_returns_not_found/1,
    gui_upload_for_inexistent_cluster_returns_not_found/1,
    gui_upload_with_invalid_package_returns_proper_error/1,
    gui_upload_with_too_large_package_returns_proper_error/1,
    gui_upload_with_confined_or_no_token_returns_proper_error/1,
    gui_upload_page_deploys_op_worker_gui_on_all_nodes/1,
    gui_upload_page_deploys_op_panel_gui_on_all_nodes/1,
    gui_upload_page_deploys_harvester_gui_on_all_nodes/1,
    gui_package_verification_works/1,
    unused_packages_are_cleaned/1,
    empty_gui_is_linked_after_failed_op_worker_version_update/1,
    empty_gui_is_linked_after_failed_op_panel_version_update/1,
    custom_static_files_are_served/1,
    custom_static_files_are_served_from_legacy_location/1
]).

all() ->
    ?ALL([
        oz_worker_gui_is_set_up_after_startup,
        oz_panel_gui_setup_works,
        default_harvester_gui_is_automatically_linked,
        empty_gui_is_linked_after_provider_registration,
        op_worker_and_panel_gui_is_linked_upon_version_info_update,
        gui_is_unlinked_after_provider_deletion,
        gui_upload_requires_provider_auth,
        gui_upload_is_not_possible_for_onezone_services,
        gui_upload_for_inexistent_service_returns_not_found,
        gui_upload_for_inexistent_cluster_returns_not_found,
        gui_upload_with_invalid_package_returns_proper_error,
        gui_upload_with_too_large_package_returns_proper_error,
        gui_upload_with_confined_or_no_token_returns_proper_error,
        gui_upload_page_deploys_op_worker_gui_on_all_nodes,
        gui_upload_page_deploys_op_panel_gui_on_all_nodes,
        gui_upload_page_deploys_harvester_gui_on_all_nodes,
        gui_package_verification_works,
        unused_packages_are_cleaned,
        empty_gui_is_linked_after_failed_op_worker_version_update,
        empty_gui_is_linked_after_failed_op_panel_version_update,
        custom_static_files_are_served,
        custom_static_files_are_served_from_legacy_location
    ]).

-define(SSL_OPTS(Config), {ssl_options, [
    {hostname, oz_test_utils:oz_domain(Config)},
    {cacerts, oz_test_utils:gui_ca_certs(Config)}
]}).

-define(EMPTY_INDEX_CONTENT(Config, GuiType), read_content(
    Config, [<<"./">>, onedata:gui_prefix(GuiType), <<"/empty">>, <<"/i">>]
)).

%%%===================================================================
%%% Test functions
%%%===================================================================

oz_worker_gui_is_set_up_after_startup(Config) ->
    GuiPackagePath = oz_test_utils:get_env(Config, ozw_gui_package_path),
    {ok, GuiHash} = oz_test_utils:call_oz(Config, gui, package_hash, [GuiPackagePath]),
    Release = oz_test_utils:call_oz(Config, oz_worker, get_release_version, []),
    Build = oz_test_utils:call_oz(Config, oz_worker, get_build_version, []),

    OzIndexContent = read_content(Config, [<<"./ozw/">>, GuiHash, <<"/index.html">>]),

    ?assert(static_directory_exists(Config, [<<"./ozw/">>, GuiHash])),
    ?assert(link_exists(Config, <<"./ozw/onezone">>, GuiHash)),
    ?assert(file_is_served(Config, OzIndexContent, <<"/">>)),
    ?assert(file_is_served(Config, OzIndexContent, [<<"/ozw/">>, ?ONEZONE_CLUSTER_ID, <<"/i">>])),
    ?assert(file_is_served(Config, OzIndexContent, [<<"/ozw/">>, ?ONEZONE_CLUSTER_ID, <<"/index.html">>])),
    ?assert(version_info_is_set(Config, ?ONEZONE_CLUSTER_ID, ?WORKER, {Release, Build, GuiHash})).

oz_panel_gui_setup_works(Config) ->
    % Simulate cluster setup procedure performed by oz_panel
    Release = <<"mock-release">>,
    Build = <<"mock-build">>,
    {GuiPackage, IndexContent} = oz_test_utils:create_dummy_gui_package(),
    oz_test_utils:copy_file_to_onezone_nodes(Config, GuiPackage),
    ReleaseVersion = oz_test_utils:call_oz(Config, oz_worker, get_release_version, []),

    {ok, GuiHash} = oz_test_utils:call_oz(Config, gui_static, deploy_package, [
        ?ONEPANEL_GUI, ReleaseVersion, GuiPackage
    ]),
    ok = oz_test_utils:call_oz(Config, cluster_logic, update_version_info, [
        ?ROOT, ?ONEZONE_CLUSTER_ID, ?ONEPANEL, {Release, Build, GuiHash}
    ]),

    ?assert(static_directory_exists(Config, [<<"./onp/">>, GuiHash])),
    ?assert(link_exists(Config, <<"./onp/onezone">>, GuiHash)),
    ?assert(file_is_served(Config, IndexContent, [<<"/onp/">>, ?ONEZONE_CLUSTER_ID, <<"/i">>])),
    ?assert(file_is_served(Config, IndexContent, [<<"/onp/">>, ?ONEZONE_CLUSTER_ID, <<"/index.html">>])),
    ?assert(version_info_is_set(Config, ?ONEZONE_CLUSTER_ID, ?ONEPANEL, {Release, Build, GuiHash})).

default_harvester_gui_is_automatically_linked(Config) ->
    HarvesterId = ozt_harvesters:create(),
    HrvIndexContent = read_content(Config, [<<"./hrv/default/index.html">>]),
    
    ?assert(static_directory_exists(Config, [<<"./hrv/default">>])),
    ?assert(link_exists(Config, <<"./hrv/", HarvesterId/binary>>, <<"default">>)),
    ?assert(file_is_served(Config, HrvIndexContent, [<<"/hrv/">>, HarvesterId, <<"/i">>])),
    ?assert(file_is_served(Config, HrvIndexContent, [<<"/hrv/">>, HarvesterId, <<"/index.html">>])).


empty_gui_is_linked_after_provider_registration(Config) ->
    {ok, {ProviderId, _}} = oz_test_utils:create_provider(Config, ?PROVIDER_NAME1),
    ClusterId = ProviderId,

    ?assert(static_directory_exists(Config, [<<"./opw/">>, <<"empty">>])),
    ?assert(link_exists(Config, [<<"./opw/">>, ClusterId], <<"empty">>)),
    ?assert(file_is_served(Config, ?EMPTY_INDEX_CONTENT(Config, ?OP_WORKER_GUI), [<<"/opw/">>, ClusterId, <<"/i">>])),
    ?assert(file_is_served(Config, ?EMPTY_INDEX_CONTENT(Config, ?OP_WORKER_GUI), [<<"/opw/">>, ClusterId, <<"/index.html">>])),
    ?assert(version_info_is_set(Config, ClusterId, ?WORKER, {?DEFAULT_RELEASE_VERSION, ?DEFAULT_BUILD_VERSION, ?EMPTY_GUI_HASH})),

    ?assert(static_directory_exists(Config, [<<"./onp/">>, <<"empty">>])),
    ?assert(link_exists(Config, [<<"./onp/">>, ClusterId], <<"empty">>)),
    ?assert(file_is_served(Config, ?EMPTY_INDEX_CONTENT(Config, ?ONEPANEL_GUI), [<<"/onp/">>, ClusterId, <<"/i">>])),
    ?assert(file_is_served(Config, ?EMPTY_INDEX_CONTENT(Config, ?ONEPANEL_GUI), [<<"/onp/">>, ClusterId, <<"/index.html">>])),
    ?assert(version_info_is_set(Config, ClusterId, ?ONEPANEL, {?DEFAULT_RELEASE_VERSION, ?DEFAULT_BUILD_VERSION, ?EMPTY_GUI_HASH})).

<commit_msg>VFS-6544 Added default harvester gui update test<commit_after>%%%-------------------------------------------------------------------
%%% @author <NAME>
%%% @copyright (C) 2019 ACK CYFRONET AGH
%%% This software is released under the MIT license
%%% cited in 'LICENSE.txt'.
%%% @end
%%%-------------------------------------------------------------------
%%% @doc
%%% This file contains tests concerning the mechanisms of uploading and linking
%%% static GUI files of different services.
%%% @end
%%%-------------------------------------------------------------------
-module(gui_static_distribution_test_SUITE).
-author("<NAME>").

-include("http/rest.hrl").
-include("registered_names.hrl").
-include("datastore/oz_datastore_models.hrl").
-include_lib("ctool/include/onedata.hrl").
-include_lib("ctool/include/privileges.hrl").
-include_lib("ctool/include/errors.hrl").
-include_lib("ctool/include/http/headers.hrl").
-include_lib("ctool/include/test/test_utils.hrl").
-include_lib("ctool/include/test/assertions.hrl").
-include_lib("ctool/include/test/performance.hrl").

-include("api_test_utils.hrl").

%% API
-export([
    all/0,
    init_per_suite/1, end_per_suite/1,
    init_per_testcase/2, end_per_testcase/2
]).
-export([
    oz_worker_gui_is_set_up_after_startup/1,
    oz_panel_gui_setup_works/1,
    default_harvester_gui_is_automatically_linked/1,
    default_harvester_gui_is_updated_on_deployment/1,
    empty_gui_is_linked_after_provider_registration/1,
    op_worker_and_panel_gui_is_linked_upon_version_info_update/1,
    gui_is_unlinked_after_provider_deletion/1,
    gui_upload_requires_provider_auth/1,
    gui_upload_is_not_possible_for_onezone_services/1,
    gui_upload_for_inexistent_service_returns_not_found/1,
    gui_upload_for_inexistent_cluster_returns_not_found/1,
    gui_upload_with_invalid_package_returns_proper_error/1,
    gui_upload_with_too_large_package_returns_proper_error/1,
    gui_upload_with_confined_or_no_token_returns_proper_error/1,
    gui_upload_page_deploys_op_worker_gui_on_all_nodes/1,
    gui_upload_page_deploys_op_panel_gui_on_all_nodes/1,
    gui_upload_page_deploys_harvester_gui_on_all_nodes/1,
    gui_package_verification_works/1,
    unused_packages_are_cleaned/1,
    empty_gui_is_linked_after_failed_op_worker_version_update/1,
    empty_gui_is_linked_after_failed_op_panel_version_update/1,
    custom_static_files_are_served/1,
    custom_static_files_are_served_from_legacy_location/1
]).

all() ->
    ?ALL([
        oz_worker_gui_is_set_up_after_startup,
        oz_panel_gui_setup_works,
        default_harvester_gui_is_automatically_linked,
        default_harvester_gui_is_updated_on_deployment,
        empty_gui_is_linked_after_provider_registration,
        op_worker_and_panel_gui_is_linked_upon_version_info_update,
        gui_is_unlinked_after_provider_deletion,
        gui_upload_requires_provider_auth,
        gui_upload_is_not_possible_for_onezone_services,
        gui_upload_for_inexistent_service_returns_not_found,
        gui_upload_for_inexistent_cluster_returns_not_found,
        gui_upload_with_invalid_package_returns_proper_error,
        gui_upload_with_too_large_package_returns_proper_error,
        gui_upload_with_confined_or_no_token_returns_proper_error,
        gui_upload_page_deploys_op_worker_gui_on_all_nodes,
        gui_upload_page_deploys_op_panel_gui_on_all_nodes,
        gui_upload_page_deploys_harvester_gui_on_all_nodes,
        gui_package_verification_works,
        unused_packages_are_cleaned,
        empty_gui_is_linked_after_failed_op_worker_version_update,
        empty_gui_is_linked_after_failed_op_panel_version_update,
        custom_static_files_are_served,
        custom_static_files_are_served_from_legacy_location
    ]).

-define(SSL_OPTS(Config), {ssl_options, [
    {hostname, oz_test_utils:oz_domain(Config)},
    {cacerts, oz_test_utils:gui_ca_certs(Config)}
]}).

-define(EMPTY_INDEX_CONTENT(Config, GuiType), read_content(
    Config, [<<"./">>, onedata:gui_prefix(GuiType), <<"/empty">>, <<"/i">>]
)).

%%%===================================================================
%%% Test functions
%%%===================================================================

oz_worker_gui_is_set_up_after_startup(Config) ->
    GuiPackagePath = oz_test_utils:get_env(Config, ozw_gui_package_path),
    {ok, GuiHash} = oz_test_utils:call_oz(Config, gui, package_hash, [GuiPackagePath]),
    Release = oz_test_utils:call_oz(Config, oz_worker, get_release_version, []),
    Build = oz_test_utils:call_oz(Config, oz_worker, get_build_version, []),

    OzIndexContent = read_content(Config, [<<"./ozw/">>, GuiHash, <<"/index.html">>]),

    ?assert(static_directory_exists(Config, [<<"./ozw/">>, GuiHash])),
    ?assert(link_exists(Config, <<"./ozw/onezone">>, GuiHash)),
    ?assert(file_is_served(Config, OzIndexContent, <<"/">>)),
    ?assert(file_is_served(Config, OzIndexContent, [<<"/ozw/">>, ?ONEZONE_CLUSTER_ID, <<"/i">>])),
    ?assert(file_is_served(Config, OzIndexContent, [<<"/ozw/">>, ?ONEZONE_CLUSTER_ID, <<"/index.html">>])),
    ?assert(version_info_is_set(Config, ?ONEZONE_CLUSTER_ID, ?WORKER, {Release, Build, GuiHash})).

oz_panel_gui_setup_works(Config) ->
    % Simulate cluster setup procedure performed by oz_panel
    Release = <<"mock-release">>,
    Build = <<"mock-build">>,
    {GuiPackage, IndexContent} = oz_test_utils:create_dummy_gui_package(),
    oz_test_utils:copy_file_to_onezone_nodes(Config, GuiPackage),
    ReleaseVersion = oz_test_utils:call_oz(Config, oz_worker, get_release_version, []),

    {ok, GuiHash} = oz_test_utils:call_oz(Config, gui_static, deploy_package, [
        ?ONEPANEL_GUI, ReleaseVersion, GuiPackage
    ]),
    ok = oz_test_utils:call_oz(Config, cluster_logic, update_version_info, [
        ?ROOT, ?ONEZONE_CLUSTER_ID, ?ONEPANEL, {Release, Build, GuiHash}
    ]),

    ?assert(static_directory_exists(Config, [<<"./onp/">>, GuiHash])),
    ?assert(link_exists(Config, <<"./onp/onezone">>, GuiHash)),
    ?assert(file_is_served(Config, IndexContent, [<<"/onp/">>, ?ONEZONE_CLUSTER_ID, <<"/i">>])),
    ?assert(file_is_served(Config, IndexContent, [<<"/onp/">>, ?ONEZONE_CLUSTER_ID, <<"/index.html">>])),
    ?assert(version_info_is_set(Config, ?ONEZONE_CLUSTER_ID, ?ONEPANEL, {Release, Build, GuiHash})).

default_harvester_gui_is_automatically_linked(Config) ->
    HarvesterId = ozt_harvesters:create(),
    HrvIndexContent = read_content(Config, [<<"./hrv/default/index.html">>]),
    
    ?assert(static_directory_exists(Config, [<<"./hrv/default">>])),
    ?assert(link_exists(Config, <<"./hrv/", HarvesterId/binary>>, <<"default">>)),
    ?assert(file_is_served(Config, HrvIndexContent, [<<"/hrv/">>, HarvesterId, <<"/i">>])),
    ?assert(file_is_served(Config, HrvIndexContent, [<<"/hrv/">>, HarvesterId, <<"/index.html">>])).


default_harvester_gui_is_updated_on_deployment(Config) ->
    {TmpPath, NewHrvIndexContent} = oz_test_utils:create_dummy_gui_package(),
    ?assertNotEqual(NewHrvIndexContent, read_content(Config, [<<"./hrv/default/index.html">>])),
    
    % replace harvester gui package on all nodes
    Path = oz_test_utils:get_env(Config, default_hrv_gui_package_path),
    AbsPath = oz_test_utils:call_oz(Config, filename, absname, [Path]),
    {ok, Package} = file:read_file(TmpPath),
    Nodes = ?config(oz_worker_nodes, Config),
    lists:foreach(fun(Node) ->
        ok = rpc:call(Node, filelib, ensure_dir, [AbsPath]),
        ok = rpc:call(Node, file, write_file, [AbsPath, Package])
    end, Nodes),
    
    oz_test_utils:call_oz(Config, harvester_logic, deploy_default_gui_package, []),
    ?assertEqual(NewHrvIndexContent, read_content(Config, [<<"./hrv/default/index.html">>])).


empty_gui_is_linked_after_provider_registration(Config) ->
    {ok, {ProviderId, _}} = oz_test_utils:create_provider(Config, ?PROVIDER_NAME1),
    ClusterId = ProviderId,

    ?assert(static_directory_exists(Config, [<<"./opw/">>, <<"empty">>])),
    ?assert(link_exists(Config, [<<"./opw/">>, ClusterId], <<"empty">>)),
    ?assert(file_is_served(Config, ?EMPTY_INDEX_CONTENT(Config, ?OP_WORKER_GUI), [<<"/opw/">>, ClusterId, <<"/i">>])),
    ?assert(file_is_served(Config, ?EMPTY_INDEX_CONTENT(Config, ?OP_WORKER_GUI), [<<"/opw/">>, ClusterId, <<"/index.html">>])),
    ?assert(version_info_is_set(Config, ClusterId, ?WORKER, {?DEFAULT_RELEASE_VERSION, ?DEFAULT_BUILD_VERSION, ?EMPTY_GUI_HASH})),

    ?assert(static_directory_exists(Config, [<<"./onp/">>, <<"empty">>])),
    ?assert(link_exists(Config, [<<"./onp/">>, ClusterId], <<"empty">>)),
    ?assert(file_is_served(Config, ?EMPTY_INDEX_CONTENT(Config, ?ONEPANEL_GUI), [<<"/onp/">>, ClusterId, <<"/i">>])),
    ?assert(file_is_served(Config, ?EMPTY_INDEX_CONTENT(Config, ?ONEPANEL_GUI), [<<"/onp/">>, ClusterId, <<"/index.html">>])),
    ?assert(version_info_is_set(Config, ClusterId, ?ONEPANEL, {?DEFAULT_RELEASE_VERSION, ?DEFAULT_BUILD_VERSION, ?EMPTY_GUI_HASH})).


{'fraction_non_alphanumeric': 0.18093881668743694, 'fraction_numerical': 0.004094712479971515, 'mean_word_length': 5.262356001486436, 'pattern_counts': {'":': 0, '<': 187, '<?xml version=': 0, '>': 199, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5709480', 'n_tokens_mistral': 6271, 'n_tokens_neox': 6009, 'n_words': 674}