From 16404fc473ce233d3ce1153e75f7c21db545d939 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Imobach=20Gonz=C3=A1lez=20Sosa?= Date: Wed, 4 Apr 2018 11:32:32 +0100 Subject: [PATCH] Move license retrieving logic to License class --- .../packages/src/lib/y2packager/license.rb | 84 +++++++++---- .../src/lib/y2packager/licenses_fetchers.rb | 26 ++++ .../packages/test/y2packager/license_test.rb | 111 +++++++++++++++++- 3 files changed, 195 insertions(+), 26 deletions(-) create mode 100644 library/packages/src/lib/y2packager/licenses_fetchers.rb diff --git a/library/packages/src/lib/y2packager/license.rb b/library/packages/src/lib/y2packager/license.rb index 75500b7cb..1a1622a71 100644 --- a/library/packages/src/lib/y2packager/license.rb +++ b/library/packages/src/lib/y2packager/license.rb @@ -12,16 +12,14 @@ require "yast" require "digest" +require "y2packager/licenses_fetchers" module Y2Packager # Represent a License which could be the same for multiple products. # - # This class stores the license ID and the traslated content of the license - # for different languages. + # This class represents a license. class License DEFAULT_LANG = "en_US".freeze - # @return [String] License unique identifier - attr_reader :id # @return [Boolean] whether the license has been accepted or not attr_reader :accepted @@ -29,23 +27,81 @@ class License # @return [Hash] language -> content attr_reader :translations + # @return [Y2Packager::LicensesFetchers::Base] License fetcher object + attr_reader :fetcher + alias_method :accepted?, :accepted + class << self + # Find a license for a given product + # + # @param product_name [String] Product's name + # @param source [:rpm,:url] Source to get the license from. For the time being, + # only :rpm is really supported. + # @return [License] + def find(product_name, source) + return cache[product_name] if cache[product_name] + + # This could be done in the constructor. + fetcher = LicensesFetchers.for(source) + new_license = License.new(LicensesFetchers::Rpm.new(product_name)) + return unless new_license.id + + eq_license = cache.values.find { |l| l.id == new_license.id } + license = eq_license || new_license + cache[product_name] = license + end + + def clear_cache + @cache = nil + end + + private def cache + @cache ||= {} + end + end + # Constructor # # @param options [Hash] - def initialize(options = {}) + def initialize(fetcher) @accepted = false - @id = id_for(options) - @translations = { DEFAULT_LANG => options[:content] } + @fetcher = fetcher + @translations = {} + end + + # License unique identifier + # + # This identifier is based on the given default language translation. + # + # @return [String] Unique identifier + def id + @id ||= Digest::MD5.hexdigest(content_for(DEFAULT_LANG)) end # Return the license translated content for the given language # + # It will return the empty string ("") if the license does not exist + # # @param [String] language # @return [String,nil] the license translated content or nil if not found def content_for(lang = DEFAULT_LANG) - translations[lang] + return @translations[lang] if @translations[lang] + content = fetcher.license_content(lang) + return add_content_for(lang, content) if content + content_for(DEFAULT_LANG) unless lang == DEFAULT_LANG + end + + # FIXME: Probably the locales should be obtained through the licenses + # translations, and probably could be initialized the first time a license + # is instantiated. + def locales + fetcher.license_locales + end + + def license_confirmation_required? + # FIXME + true end # Add the license translated content for the given language @@ -66,17 +122,5 @@ def accept! def reject! @accepted = false end - - private - - # Generate the license unique identifier based on the given options. - # Currently the id is obtained using the MD5 digest of te license's - # content (in the default language). - # - # @param options [Hash] License map options - # @return [String] MD5 digest of the license's content - def id_for(options) - Digest::MD5.hexdigest(options[:content]) - end end end diff --git a/library/packages/src/lib/y2packager/licenses_fetchers.rb b/library/packages/src/lib/y2packager/licenses_fetchers.rb new file mode 100644 index 000000000..f3fdd3689 --- /dev/null +++ b/library/packages/src/lib/y2packager/licenses_fetchers.rb @@ -0,0 +1,26 @@ +# ------------------------------------------------------------------------------ +# Copyright (c) 2018 SUSE LLC, All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of version 2 of the GNU General Public License as published by the +# Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# ------------------------------------------------------------------------------ + +require "yast" +require "y2packager/licenses_fetchers/rpm" +require "y2packager/licenses_fetchers/url" + +module Y2Packager + module LicensesFetchers + # Return the licenses proper fetcher for a given source + # + # @param source [Symbol] :rpm or :url + def self.for(source) + const_get(source.to_s.capitalize) + end + end +end diff --git a/library/packages/test/y2packager/license_test.rb b/library/packages/test/y2packager/license_test.rb index 1fea4a10f..53b53435e 100755 --- a/library/packages/test/y2packager/license_test.rb +++ b/library/packages/test/y2packager/license_test.rb @@ -1,30 +1,129 @@ #!/usr/bin/env rspec +# ------------------------------------------------------------------------------ +# Copyright (c) 2018 SUSE LLC, All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of version 2 of the GNU General Public License as published by the +# Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# ------------------------------------------------------------------------------ require_relative "../test_helper" require "y2packager/license" describe Y2Packager::License do - let(:license) { Y2Packager::License.new(content: "dummy content") } + subject(:license) { Y2Packager::License.new(fetcher) } + + let(:fetcher) do + instance_double(Y2Packager::LicensesFetchers::Rpm, license_content: "license") + end + + before do + described_class.clear_cache + allow(Y2Packager::LicensesFetchers::Rpm).to receive(:new).and_return(fetcher) + end + + describe ".find" do + it "returns a license for the given product" do + license = described_class.find("SLES", :rpm) + expect(license).to be_a(Y2Packager::License) + end + + context "when a license with the same ID was already retrieved" do + it "returns the already retrieved instance" do + sles_license = described_class.find("SLES", :rpm) + sled_license = described_class.find("SLED", :rpm) + expect(sles_license).to be(sled_license) + end + end + + context "when no license with the same ID was already retrieved" do + before do + allow(fetcher).to receive(:license_content).and_return("sles license", "sled license") + end + + it "returns a new license instance" do + sles_license = described_class.find("SLES", :rpm) + sled_license = described_class.find("SLED", :rpm) + expect(sles_license).to_not be(sled_license) + expect(sles_license.id).to_not eq(sled_license.id) + end + end + end + + describe "#id" do + before do + allow(fetcher).to receive(:license_content).and_return("content") + end + + it "returns the license unique identifier" do + expect(license.id).to eq("9a0364b9e99bb480dd25e1f0284c8555") + end + end describe "#content_for" do - it "returns the license content for the given language if exists" do - expect(license.content_for(described_class::DEFAULT_LANG)).to eq("dummy content") + let(:lang) { "es_ES" } + + context "when no language is given" do + it "returns the license content for the default language" do + expect(fetcher).to receive(:license_content).with(described_class::DEFAULT_LANG) + .and_return("dummy content") + expect(license.content_for).to eq("dummy content") + end + end + + it "returns the license content for the given language" do + expect(fetcher).to receive(:license_content).with(lang) + .and_return("dummy content") + expect(license.content_for(lang)).to eq("dummy content") + end + + context "when there is no translation for the given language" do + before do + allow(fetcher).to receive(:license_content).with(lang).and_return(nil) + allow(fetcher).to receive(:license_content).with(described_class::DEFAULT_LANG) + .and_return("dummy content") + end + + it "returns the license content for the default language" do + expect(license.content_for(lang)).to eq("dummy content") + end end - it "returns nil if there is no content for the given language" do - expect(license.content_for("es_ES")).to eq(nil) + context "license content for the given languages was already retrieved" do + before do + allow(fetcher).to receive(:license_content).with(lang).and_return("content") + license.content_for(lang) + end + + it "returns cached content" do + expect(fetcher).to_not receive(:license_content) + expect(license.content_for(lang)).to eq("content") + end end end describe "#add_content_for" do it "adds a new translated content to the license" do - expect(license.content_for("es_ES")).to eq(nil) expect(license.add_content_for("es_ES", "contenido ficticio")) expect(license.content_for("es_ES")).to eq("contenido ficticio") end end + describe "#locales" do + before do + allow(fetcher).to receive(:license_locales).and_return(["en_US", "cz_CZ"]) + end + + it "returns list of available translations for the license" do + expect(license.locales).to eq(["en_US", "cz_CZ"]) + end + end + describe "#accept!" do it "marks the license as accepted" do expect(license.accepted?).to be(false)