diff --git a/.ci/unit-tests/inspec.sh b/.ci/unit-tests/inspec.sh index eb1427683a1f..b47977f743cd 100755 --- a/.ci/unit-tests/inspec.sh +++ b/.ci/unit-tests/inspec.sh @@ -3,4 +3,10 @@ set -e set -x -echo 'TODO slevenick write tests' \ No newline at end of file +echo 'TODO slevenick write tests' +pushd "magic-modules/build/inspec/libraries" + +bundle install +rspec -I . ../test/unit/* + +popd \ No newline at end of file diff --git a/products/compute/inspec.yaml b/products/compute/inspec.yaml index bcd603cee34d..0c32199b9f4d 100644 --- a/products/compute/inspec.yaml +++ b/products/compute/inspec.yaml @@ -20,87 +20,85 @@ manifest: !ruby/object:Provider::Inspec::Manifest description: | InSpec resources for verifying GCP infrastructure overrides: !ruby/object:Provider::ResourceOverrides - Address: !ruby/object:Provider::Chef::ResourceOverride + Address: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - Autoscaler: !ruby/object:Provider::Chef::ResourceOverride + Autoscaler: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - BackendBucket: !ruby/object:Provider::Chef::ResourceOverride + BackendBucket: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - BackendService: !ruby/object:Provider::Chef::ResourceOverride + BackendService: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - Disk: !ruby/object:Provider::Chef::ResourceOverride + Disk: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - DiskType: !ruby/object:Provider::Chef::ResourceOverride + DiskType: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - Firewall: !ruby/object:Provider::Chef::ResourceOverride + ForwardingRule: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - ForwardingRule: !ruby/object:Provider::Chef::ResourceOverride + GlobalAddress: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - GlobalAddress: !ruby/object:Provider::Chef::ResourceOverride + GlobalForwardingRule: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - GlobalForwardingRule: !ruby/object:Provider::Chef::ResourceOverride + HealthCheck: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - HealthCheck: !ruby/object:Provider::Chef::ResourceOverride + HttpHealthCheck: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - HttpHealthCheck: !ruby/object:Provider::Chef::ResourceOverride + HttpsHealthCheck: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - HttpsHealthCheck: !ruby/object:Provider::Chef::ResourceOverride + Image: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - Image: !ruby/object:Provider::Chef::ResourceOverride + InstanceGroup: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - Instance: !ruby/object:Provider::Chef::ResourceOverride + InstanceGroupManager: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - InstanceGroup: !ruby/object:Provider::Chef::ResourceOverride + InstanceTemplate: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - InstanceGroupManager: !ruby/object:Provider::Chef::ResourceOverride + InterconnectAttachment: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - InstanceTemplate: !ruby/object:Provider::Chef::ResourceOverride + License: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - InterconnectAttachment: !ruby/object:Provider::Chef::ResourceOverride + MachineType: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - License: !ruby/object:Provider::Chef::ResourceOverride + Network: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - MachineType: !ruby/object:Provider::Chef::ResourceOverride + Region: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - Network: !ruby/object:Provider::Chef::ResourceOverride + RegionAutoscaler: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - Region: !ruby/object:Provider::Chef::ResourceOverride + RegionDisk: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - RegionAutoscaler: !ruby/object:Provider::Chef::ResourceOverride + RegionDiskType: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - RegionDisk: !ruby/object:Provider::Chef::ResourceOverride + Route: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - RegionDiskType: !ruby/object:Provider::Chef::ResourceOverride + Router: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - Route: !ruby/object:Provider::Chef::ResourceOverride + Snapshot: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - Router: !ruby/object:Provider::Chef::ResourceOverride + SslCertificate: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - Snapshot: !ruby/object:Provider::Chef::ResourceOverride + SslPolicy: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - SslCertificate: !ruby/object:Provider::Chef::ResourceOverride + Subnetwork: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - SslPolicy: !ruby/object:Provider::Chef::ResourceOverride + TargetHttpProxy: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - Subnetwork: !ruby/object:Provider::Chef::ResourceOverride + TargetHttpsProxy: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - TargetHttpProxy: !ruby/object:Provider::Chef::ResourceOverride + TargetPool: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - TargetHttpsProxy: !ruby/object:Provider::Chef::ResourceOverride + TargetTcpProxy: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - TargetPool: !ruby/object:Provider::Chef::ResourceOverride + TargetVpnGateway: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - TargetTcpProxy: !ruby/object:Provider::Chef::ResourceOverride + TargetSslProxy: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - TargetVpnGateway: !ruby/object:Provider::Chef::ResourceOverride + UrlMap: !ruby/object:Provider::Inspec::ResourceOverride exclude: true - TargetSslProxy: !ruby/object:Provider::Chef::ResourceOverride - exclude: true - UrlMap: !ruby/object:Provider::Chef::ResourceOverride - exclude: true - VpnTunnel: !ruby/object:Provider::Chef::ResourceOverride + VpnTunnel: !ruby/object:Provider::Inspec::ResourceOverride exclude: true files: !ruby/object:Provider::Config::Files + copy: +<%= lines(indent(compile('provider/inspec/common~copy.yaml'), 4)) -%> style: functions: changelog: diff --git a/provider/inspec.rb b/provider/inspec.rb index a904cadcef75..922486e815a1 100644 --- a/provider/inspec.rb +++ b/provider/inspec.rb @@ -43,7 +43,7 @@ def property_override # This function uses the resource templates to create singular and plural # resources that can be used by InSpec def generate_resource(data) - target_folder = File.join(data[:output_folder], 'inspec') + target_folder = File.join(data[:output_folder], 'libraries') FileUtils.mkpath target_folder name = data[:object].name.underscore generate_resource_file data.clone.merge( @@ -58,7 +58,7 @@ def generate_resource(data) generate_documentation(data) end - # Generates InSpec markdown documents for the resource + # Generates InSpec markdown documents for the resource def generate_documentation(data) name = data[:object].name.underscore docs_folder = File.join(data[:output_folder], 'docs', 'resources') @@ -74,8 +74,12 @@ def format_url(url) url.split("\n").join('') end - # TODO? - def generate_resource_tests(data) end + # Copies InSpec unit tests to build folder + def generate_resource_tests(data) + target_folder = File.join(data[:output_folder], 'test/unit') + FileUtils.mkpath target_folder + FileUtils.cp_r 'templates/inspec/tests/.', target_folder + end def generate_base_property(data) end @@ -178,7 +182,7 @@ def resource_name(object, product_ns) "google_#{product_ns.downcase}_#{object.name.underscore}" end - def sub_property_descriptions(property) + def sub_property_descriptions(property) if nested_object?(property) return property.properties.map \ { |prop| " * `#{prop.name}`: #{prop.description}" }.join("\n") @@ -188,7 +192,8 @@ def sub_property_descriptions(property) return property.item_type.properties.map \ { |prop| " * `#{prop.name}`: #{prop.description}" }.join("\n") end + # rubocop:enable Style/GuardClause end - # rubocop:enable Style/GuardClause end + # rubocop:enable Metrics/ClassLength end diff --git a/provider/inspec/common~copy.yaml b/provider/inspec/common~copy.yaml new file mode 100644 index 000000000000..a64db1e1d2e9 --- /dev/null +++ b/provider/inspec/common~copy.yaml @@ -0,0 +1,17 @@ +# Copyright 2017 Google Inc. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# These files are okay to be copied "AS-IS" to the module's final destination: + +'libraries/google/hash_utils.rb': 'google/hash_utils.rb' +'libraries/google/string_utils.rb': 'google/string_utils.rb' diff --git a/templates/inspec/nested_object.erb b/templates/inspec/nested_object.erb index 9a20dd7bb7b1..42f810a8bedc 100644 --- a/templates/inspec/nested_object.erb +++ b/templates/inspec/nested_object.erb @@ -37,7 +37,7 @@ module Google <% nested_properties.each do |prop| -%> <% if time?(prop) - init = "Time.new(args['#{prop.api_name}'])" + init = "DateTime.parse(args['#{prop.api_name}'])" elsif primitive?(prop) init = "args['#{prop.api_name}']" elsif typed_array?(prop) diff --git a/templates/inspec/plural_resource.erb b/templates/inspec/plural_resource.erb index f56ea78f27ae..ea1a43a4f2bf 100644 --- a/templates/inspec/plural_resource.erb +++ b/templates/inspec/plural_resource.erb @@ -16,6 +16,7 @@ <%= lines(autogen_notice :ruby) -%> +require 'inspec/resource' class <%= object.name -%>s < Inspec.resource(1) <% diff --git a/templates/inspec/singular_resource.erb b/templates/inspec/singular_resource.erb index d5e59709f0ae..64d1d39612b4 100644 --- a/templates/inspec/singular_resource.erb +++ b/templates/inspec/singular_resource.erb @@ -52,10 +52,16 @@ class <%= object.name -%> < Inspec.resource(1) parse unless @fetched.nil? end <% else # object.self_link_query.nil? -%> - # TODO(slevenick) for other products - def initialize(params) - raise 'Not implemented' - end + def initialize(params) + @fetched = <%= method_call('fetch_wrapped_resource', + [ + 'params', + "'#{object.kind}'", + "'#{object.self_link_query.kind}'", + "'#{object.self_link_query.items}'" + ], 2) %> + parse unless @fetched.nil? + end <% end # object.self_link_query.nil? -%> def fetch_resource(params) @@ -84,7 +90,7 @@ class <%= object.name -%> < Inspec.resource(1) name = prop.out_name if time?(prop) - init = "Time.new(@fetched['#{prop.api_name}'])" + init = "DateTime.parse(@fetched['#{prop.api_name}'])" elsif primitive?(prop) init = "@fetched['#{prop.api_name}']" elsif typed_array?(prop) @@ -102,4 +108,45 @@ class <%= object.name -%> < Inspec.resource(1) def exists? !@fetched.nil? end + +<% unless object.self_link_query.nil? -%> + def fetch_wrapped_resource(params, kind, wrap_kind, wrap_path) + result = fetch_resource(params, wrap_kind) + return if result.nil? || !result.key?(wrap_path) + result = unwrap_resource(result[wrap_path], params) + return if result.nil? + raise "Incorrect result: #{result['kind']} (expected #{kind})" \ + unless result['kind'] == kind + result + end + + + def unwrap_resource(result, resource) + query_predicate = unwrap_resource_filter(resource) + matches = result.select do |entry| + query_predicate.all? do |k, v| + entry[k.id2name] == v + end + end + raise "More than 1 result found: #{matches}" if matches.size > 1 + return if matches.empty? + matches.first + end + +<% + urf_code = [ + '{', + indent_list( + Hash[object.identity.map { |i| [i, "resource[:#{property_out_name(i)}]"] }] + .map { |k, v| "#{k.out_name}: #{v}" }, 2 + ), + '}' + ] +-%> + def unwrap_resource_filter(resource) + self.class.unwrap_resource_filter(resource) + end +<%= lines(indent(emit_method('self.unwrap_resource_filter', %w[resource], + urf_code, file_relative), 2), 1) -%> +<% end # object.self_link_query.nil? -%> end diff --git a/templates/inspec/tests/firewall_test.rb b/templates/inspec/tests/firewall_test.rb new file mode 100644 index 000000000000..b5ac19ad711d --- /dev/null +++ b/templates/inspec/tests/firewall_test.rb @@ -0,0 +1,61 @@ +require 'google_compute_firewall' + +class FirewallTest < Firewall + def initialize(data) + @fetched = data + end +end +description = "My description" +firewall_fixture = {"kind"=>"compute#firewall", + "id"=>"960238098441931407", + "creationTimestamp"=>"2018-10-11T22:42:56.000-07:00", + "name"=>"default-uuaca3r2wn7yqlbdyzue5lrn", + "description"=>description, + "network"=> + "https://www.googleapis.com/compute/v1/projects/sam-inspec/global/networks/default", + "priority"=>1000, + "sourceRanges"=> + ["103.104.152.0/22", + "104.132.0.0/14", + "113.197.104.0/22", + "185.25.28.0/22", + "193.200.222.0/24", + "89.207.224.0/21"], + "targetTags"=>["https-server"], + "allowed"=>[{"IPProtocol"=>"tcp", "ports"=>["443"]}], + "denied"=>[{"IPProtocol"=>"udp", "ports"=>["555"]}], + "direction"=>"INGRESS", + "disabled"=>false, + "selfLink"=> + "https://www.googleapis.com/compute/v1/projects/sam-inspec/global/firewalls/default-uuaca3r2wn7yqlbdyzue5lrn"} + + +RSpec.describe Firewall, '#parse' do + before do + @firewall_mock = FirewallTest.new(firewall_fixture) + @firewall_mock.parse + end + context 'firewall attributes' do + it { expect(@firewall_mock.exists?).to be true } + it { expect(@firewall_mock.creation_timestamp).to eq Time.at(1539322976).to_datetime } + it { expect(@firewall_mock.description).to eq description } + it { expect(@firewall_mock.allowed.size).to be 1 } + it { expect(@firewall_mock.allowed[0].ip_protocol).to eq 'tcp' } + it { expect(@firewall_mock.allowed[0].ports).to include "443" } + it { expect(@firewall_mock.denied.size).to be 1 } + it { expect(@firewall_mock.denied[0].ip_protocol).to eq 'udp' } + it { expect(@firewall_mock.denied[0].ports).to include "555" } + it { expect(@firewall_mock.direction).to eq 'INGRESS' } + it { expect(@firewall_mock.network).to match('/default$') } + it { expect(@firewall_mock.source_ranges).to include "113.197.104.0/22" } + + end +end + + +no_firewall = FirewallTest.new(nil) +RSpec.describe Firewall, "#parse" do + it "does not exist" do + expect(no_firewall.exists?).to be false + end +end \ No newline at end of file diff --git a/templates/inspec/tests/firewalls_test.rb b/templates/inspec/tests/firewalls_test.rb new file mode 100644 index 000000000000..4065cd6b77bc --- /dev/null +++ b/templates/inspec/tests/firewalls_test.rb @@ -0,0 +1,121 @@ +require 'google_compute_firewalls' + +class FirewallsTest < Firewalls + def fetch_resource(data) + return data + end +end + +firewalls_fixture = {"kind"=>"compute#firewallList", + "id"=>"projects/sam-inspec/global/firewalls", + "items"=> + [{"kind"=>"compute#firewall", + "id"=>"2182788659368790689", + "creationTimestamp"=>"2018-10-11T22:42:38.647-07:00", + "name"=>"default-2wnao3jebww7ldrn463stwke", + "description"=> + "Desc", + "network"=> + "https://www.googleapis.com/compute/v1/projects/sam-inspec/global/networks/default", + "priority"=>1000, + "sourceRanges"=> + ["103.104.152.0/22", + "104.132.0.0/14", + "113.197.104.0/22", + "185.25.28.0/22", + "193.200.222.0/24", + "89.207.224.0/21"], + "allowed"=>[{"IPProtocol"=>"tcp", "ports"=>["22", "3389"]}], + "direction"=>"INGRESS", + "disabled"=>false, + "selfLink"=> + "https://www.googleapis.com/compute/v1/projects/sam-inspec/global/firewalls/default-2wnao3jebww7ldrn463stwke"}, + {"kind"=>"compute#firewall", + "id"=>"8832388878237010597", + "creationTimestamp"=>"2018-10-11T22:42:34.846-07:00", + "name"=>"default-7mzjmae3tlidh4yoidvnpe53", + "description"=> + "Description 2", + "network"=> + "https://www.googleapis.com/compute/v1/projects/sam-inspec/global/networks/default", + "priority"=>1000, + "sourceRanges"=> + ["108.170.224.0/19", + "108.177.8.0/21", + "108.177.80.0/20", + "108.177.96.0/19", + "172.102.8.0/21", + "172.217.0.0/19", + "172.217.128.0/19", + "172.217.160.0/20", + "172.217.176.1/32", + "172.217.176.2/32", + "172.217.192.0/19", + "172.217.64.0/18", + "172.253.50.0/23", + "172.253.64.0/20", + "173.194.0.0/16", + "185.150.148.0/22", + "192.104.160.0/23", + "209.107.176.0/20", + "209.85.128.0/17", + "216.239.32.0/19", + "216.252.220.0/22", + "216.58.192.0/19", + "64.233.160.0/19", + "66.102.0.0/20", + "66.249.64.0/19", + "72.14.192.0/18", + "74.125.0.0/16", + "8.8.4.0/24", + "8.8.8.0/24"], + "targetTags"=>["https-server"], + "allowed"=>[{"IPProtocol"=>"tcp", "ports"=>["443"]}], + "direction"=>"INGRESS", + "disabled"=>false, + "selfLink"=> + "https://www.googleapis.com/compute/v1/projects/sam-inspec/global/firewalls/default-7mzjmae3tlidh4yoidvnpe53"}, + {"kind"=>"compute#firewall", + "id"=>"8107033807488387752", + "creationTimestamp"=>"2018-10-11T22:42:31.919-07:00", + "name"=>"default-knsku4qwwbtr3bhcf3y6vcmu", + "description"=> + "Another description", + "network"=> + "https://www.googleapis.com/compute/v1/projects/sam-inspec/global/networks/default", + "priority"=>1000, + "sourceRanges"=>["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"], + "allowed"=>[{"IPProtocol"=>"tcp"}, {"IPProtocol"=>"udp"}], + "direction"=>"INGRESS", + "disabled"=>false, + "selfLink"=> + "https://www.googleapis.com/compute/v1/projects/sam-inspec/global/firewalls/default-knsku4qwwbtr3bhcf3y6vcmu"} + ], + + "selfLink"=> + "https://www.googleapis.com/compute/v1/projects/sam-inspec/global/firewalls"} + +RSpec.describe Firewalls, '#fetch_resource' do + before do + @firewalls_mock = FirewallsTest.new(firewalls_fixture) + end + context 'firewalls plural' do + it { expect(@firewalls_mock.names.size).to eq 3 } + it { expect(@firewalls_mock.names).to include 'default-knsku4qwwbtr3bhcf3y6vcmu' } + it { expect(@firewalls_mock.names).to include 'default-7mzjmae3tlidh4yoidvnpe53' } + it { expect(@firewalls_mock.names).to include 'default-2wnao3jebww7ldrn463stwke' } + end +end + +no_firewalls_fixture = {"kind"=>"compute#firewallList", + "id"=>"projects/sam-inspec/global/firewalls", + "items"=>[], + "selfLink"=> + "https://www.googleapis.com/compute/v1/projects/sam-inspec/global/firewalls"} + +no_firewalls = FirewallsTest.new(no_firewalls_fixture) +RSpec.describe Firewalls, "#fetch_resource" do + it "no firewalls" do + expect(no_firewalls.names.size).to eq 0 + end +end \ No newline at end of file diff --git a/templates/inspec/tests/instance_test.rb b/templates/inspec/tests/instance_test.rb new file mode 100644 index 000000000000..e64f2528ceb4 --- /dev/null +++ b/templates/inspec/tests/instance_test.rb @@ -0,0 +1,103 @@ +require 'google_compute_instance' + +class InstanceTest < Instance + def initialize(data) + @fetched = data + end +end + +instance_fixture = {"kind"=>"compute#instance", + "id"=>"1154794430415066980", + "creationTimestamp"=>"2018-10-24T14:52:15.794-07:00", + "name"=>"gcp-inspec-app-mig3-4pp8", + "tags"=> + {"items"=>["allow-gcp-inspec-app-mig3", "allow-ssh"], + "fingerprint"=>"rOcaWmVHbAQ="}, + "machineType"=> + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/europe-west2-c/machineTypes/f1-micro", + "status"=>"RUNNING", + "zone"=> + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/europe-west2-c", + "networkInterfaces"=> + [{"kind"=>"compute#networkInterface", + "network"=> + "https://www.googleapis.com/compute/v1/projects/sam-inspec/global/networks/default", + "subnetwork"=> + "https://www.googleapis.com/compute/v1/projects/sam-inspec/regions/europe-west2/subnetworks/default", + "networkIP"=>"10.154.0.7", + "name"=>"nic0", + "accessConfigs"=> + [{"kind"=>"compute#accessConfig", + "type"=>"ONE_TO_ONE_NAT", + "name"=>"external-nat", + "natIP"=>"35.242.153.92", + "networkTier"=>"PREMIUM"}], + "fingerprint"=>"gqa1nAlsW2g="}], + "disks"=> + [{"kind"=>"compute#attachedDisk", + "type"=>"PERSISTENT", + "mode"=>"READ_WRITE", + "source"=> + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/europe-west2-c/disks/gcp-inspec-app-mig3-4pp8", + "deviceName"=>"persistent-disk-0", + "index"=>0, + "boot"=>true, + "autoDelete"=>true, + "licenses"=> + ["https://www.googleapis.com/compute/v1/projects/debian-cloud/global/licenses/debian-9-stretch"], + "interface"=>"SCSI", + "guestOsFeatures"=>[{"type"=>"VIRTIO_SCSI_MULTIQUEUE"}]}], + "metadata"=> + {"kind"=>"compute#metadata", + "fingerprint"=>"8sKIPG5hwJ8=", + "items"=> + [{"key"=>"instance-template", + "value"=> + "projects/577278241961/global/instanceTemplates/default-20181011161843755000000001"}, + {"key"=>"created-by", + "value"=> + "projects/577278241961/zones/europe-west2-c/instanceGroupManagers/gcp-inspec-app-mig3"}, + {"key"=>"tf_depends_id", "value"=>""}, + {"key"=>"startup-script", + "value"=>"val"}]}, + "serviceAccounts"=> + [{"email"=>"577278241961-compute@developer.gserviceaccount.com", + "scopes"=> + ["https://www.googleapis.com/auth/devstorage.full_control", + "https://www.googleapis.com/auth/logging.write", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/monitoring.write"]}], + "selfLink"=> + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/europe-west2-c/instances/gcp-inspec-app-mig3-4pp8", + "scheduling"=> + {"onHostMaintenance"=>"MIGRATE", + "automaticRestart"=>true, + "preemptible"=>false}, + "cpuPlatform"=>"Intel Broadwell", + "labelFingerprint"=>"42WmSpB8rSM=", + "startRestricted"=>false, + "deletionProtection"=>false} + +RSpec.describe Instance, "#parse" do + it "compute instance parse" do + instance_mock = InstanceTest.new(instance_fixture) + instance_mock.parse + expect(instance_mock.exists?).to be true + expect(instance_mock.disks.size).to eq 1 + expect(instance_mock.disks[0].mode).to eq 'READ_WRITE' + expect(instance_mock.disks[0].auto_delete).to be true + expect(instance_mock.scheduling.preemptible).to be false + expect(instance_mock.scheduling.automatic_restart).to be true + expect(instance_mock.service_accounts.size).to eq 1 + expect(instance_mock.service_accounts[0].email).to eq "577278241961-compute@developer.gserviceaccount.com" + expect(instance_mock.service_accounts[0].scopes).to include "https://www.googleapis.com/auth/compute" + + end +end + +RSpec.describe Instance, "none" do + it "no result" do + instance_mock = InstanceTest.new(nil) + expect(instance_mock.exists?).to be false + end +end \ No newline at end of file diff --git a/templates/inspec/tests/zone_test.rb b/templates/inspec/tests/zone_test.rb new file mode 100644 index 000000000000..8f10f459b36d --- /dev/null +++ b/templates/inspec/tests/zone_test.rb @@ -0,0 +1,38 @@ +require 'google_compute_zone' + +class ZoneTest < Zone + def initialize(data) + @fetched = data + end +end + +zone_fixture = {"kind"=>"compute#zone", + "id"=>"2231", + "creationTimestamp"=>"1989-11-28T00:00:00-05:00", + "name"=>"us-east1-b", + "description"=>"us-east1-b", + "status"=>"UP", + "region"=> + "https://www.googleapis.com/compute/v1/projects/sam-inspec/regions/us-east1", + "selfLink"=> + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/us-east1-b", + "availableCpuPlatforms"=> + ["Intel Skylake", "Intel Broadwell", "Intel Haswell"]} + +RSpec.describe Zone, "parse" do + it "zone attributes" do + zone_mock = ZoneTest.new(zone_fixture) + zone_mock.parse + expect(zone_mock.exists?).to be true + expect(zone_mock.name).to eq 'us-east1-b' + expect(zone_mock.status).to eq 'UP' + expect(zone_mock.deprecated.obsolete).to eq nil + time = Time.at(628232400).to_datetime + expect(zone_mock.creation_timestamp).to eq time + end + it "no response" do + no_zone_resource = ZoneTest.new(nil) + expect(no_zone_resource.exists?).to be false + end +end + diff --git a/templates/inspec/tests/zones_test.rb b/templates/inspec/tests/zones_test.rb new file mode 100644 index 000000000000..566f0118a91c --- /dev/null +++ b/templates/inspec/tests/zones_test.rb @@ -0,0 +1,62 @@ +require 'google_compute_zones' + +class ZonesTest < Zones + def fetch_resource(data) + return data + end +end + +zones_fixture = {"kind"=>"compute#zoneList", + "id"=>"projects/sam-inspec/zones", + "items"=> + [{"kind"=>"compute#zone", + "id"=>"2231", + "creationTimestamp"=>"1969-12-31T16:00:00.000-08:00", + "name"=>"us-east1-b", + "description"=>"us-east1-b", + "status"=>"UP", + "region"=> + "https://www.googleapis.com/compute/v1/projects/sam-inspec/regions/us-east1", + "selfLink"=> + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/us-east1-b", + "availableCpuPlatforms"=> + ["Intel Skylake", "Intel Broadwell", "Intel Haswell"]}, + {"kind"=>"compute#zone", + "id"=>"2233", + "creationTimestamp"=>"1969-12-31T16:00:00.000-08:00", + "name"=>"us-east1-c", + "description"=>"us-east1-c", + "status"=>"UP", + "region"=> + "https://www.googleapis.com/compute/v1/projects/sam-inspec/regions/us-east1", + "selfLink"=> + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/us-east1-c", + "availableCpuPlatforms"=> + ["Intel Skylake", "Intel Broadwell", "Intel Haswell"]}, + {"kind"=>"compute#zone", + "id"=>"2234", + "creationTimestamp"=>"1969-12-31T16:00:00.000-08:00", + "name"=>"us-east1-d", + "description"=>"us-east1-d", + "status"=>"UP", + "region"=> + "https://www.googleapis.com/compute/v1/projects/sam-inspec/regions/us-east1", + "selfLink"=> + "https://www.googleapis.com/compute/v1/projects/sam-inspec/zones/us-east1-d", + "availableCpuPlatforms"=> + ["Intel Skylake", "Intel Broadwell", "Intel Haswell"]}]} + +RSpec.describe Zones, "zones" do + it "plural test" do + zones_mock_resource = ZonesTest.new(zones_fixture) + expect(zones_mock_resource.names.size).to eq 3 + expect(zones_mock_resource.names).to include 'us-east1-d' + expect(zones_mock_resource.names).to include 'us-east1-b' + expect(zones_mock_resource.names).to include 'us-east1-c' + expect(zones_mock_resource.statuses).to include 'UP' + expect(zones_mock_resource.statuses.size).to eq 3 + expect(zones_mock_resource.ids).to include '2231' + expect(zones_mock_resource.ids).to include '2234' + expect(zones_mock_resource.ids).to include '2233' + end +end \ No newline at end of file