Repository: getmoto/moto

Issue:
Security Groups: Filtering doesn't match proper targets
In security group filtering, the filters are matching the groups which do NOT match the criteria. The test passes because two groups are used, and the filters do return only one result... but the id isn't tested to make sure it's the _right_ result. :-) Adding id checks results in test failure.

```
@mock_ec2
def test_get_all_security_groups():
    conn = boto.connect_ec2()
    sg1 = conn.create_security_group(name='test1', description='test1', vpc_id='vpc-mjm05d27')
    sg2 = conn.create_security_group(name='test2', description='test2')

    resp = conn.get_all_security_groups(groupnames=['test1'])
    resp.should.have.length_of(1)
    resp[0].id.should.equal(sg1.id)    # ADDED LOCALLY, FAILS

    resp = conn.get_all_security_groups(filters={'vpc_id': ['vpc-mjm05d27']})
    resp.should.have.length_of(1)
    resp[0].id.should.equal(sg1.id)    # ADDED LOCALLY, FAILS

    resp = conn.get_all_security_groups(filters={'description': ['test1']})
    resp.should.have.length_of(1)
    resp[0].id.should.equal(sg1.id)    # ADDED LOCALLY, FAILS

    resp = conn.get_all_security_groups()
    resp.should.have.length_of(2)
```

I've got a fix.



Discussion:

Resolving patch:
diff --git a/moto/ec2/models.py b/moto/ec2/models.py
--- a/moto/ec2/models.py
+++ b/moto/ec2/models.py
@@ -749,42 +749,42 @@ def create_from_cloudformation_json(cls, resource_name, cloudformation_json):
     def physical_resource_id(self):
         return self.id
 
-    def matches_filters(self, filters):
+
+    def matches_filter(self, key, filter_value):
         result = True
 
         def to_attr(filter_name):
             attr = None
 
-            if attr == 'group-name':
+            if filter_name == 'group-name':
                 attr = 'name'
-            elif attr == 'group-id':
+            elif filter_name == 'group-id':
                 attr = 'id'
+            elif filter_name == 'vpc-id':
+                attr = 'vpc_id'
             else:
                 attr = filter_name.replace('-', '_')
 
             return attr
 
-        for key, value in filters.items():
-            ret = False
-
-            if key.startswith('ip-permission'):
-                match = re.search(r"ip-permission.(*)", key)
-                ingress_attr = to_attr(match.groups()[0])
-
-                for ingress in self.ingress_rules:
-                    if getattr(ingress, ingress_attr) in filters[key]:
-                        ret = True
-                        break
-            else:
-                attr_name = to_attr(key)
-                ret = getattr(self, attr_name) in filters[key]
+        if key.startswith('ip-permission'):
+            match = re.search(r"ip-permission.(*)", key)
+            ingress_attr = to_attr(match.groups()[0])
 
-            if not ret:
-                break
+            for ingress in self.ingress_rules:
+                if getattr(ingress, ingress_attr) in filters[key]:
+                    return True
         else:
-            result = False
+            attr_name = to_attr(key)
+            return getattr(self, attr_name) in filter_value
 
-        return result
+        return False
+
+    def matches_filters(self, filters):
+        for key, value in filters.items():
+            if not self.matches_filter(key, value):
+                return False
+        return True
 
 
 class SecurityGroupBackend(object):


Test patch:
diff --git a/tests/test_ec2/test_security_groups.py b/tests/test_ec2/test_security_groups.py
--- a/tests/test_ec2/test_security_groups.py
+++ b/tests/test_ec2/test_security_groups.py
@@ -200,17 +200,24 @@ def test_authorize_group_in_vpc():
 @mock_ec2
 def test_get_all_security_groups():
     conn = boto.connect_ec2()
-    conn.create_security_group(name='test1', description='test1', vpc_id='vpc-mjm05d27')
-    conn.create_security_group(name='test2', description='test2')
+    sg1 = conn.create_security_group(name='test1', description='test1', vpc_id='vpc-mjm05d27')
+    sg2 = conn.create_security_group(name='test2', description='test2')
 
     resp = conn.get_all_security_groups(groupnames=['test1'])
     resp.should.have.length_of(1)
+    resp[0].id.should.equal(sg1.id)
+
+    resp = conn.get_all_security_groups(filters={'vpc-id': ['vpc-mjm05d27']})
+    resp.should.have.length_of(1)
+    resp[0].id.should.equal(sg1.id)
 
     resp = conn.get_all_security_groups(filters={'vpc_id': ['vpc-mjm05d27']})
     resp.should.have.length_of(1)
+    resp[0].id.should.equal(sg1.id)
 
     resp = conn.get_all_security_groups(filters={'description': ['test1']})
     resp.should.have.length_of(1)
+    resp[0].id.should.equal(sg1.id)
 
     resp = conn.get_all_security_groups()
     resp.should.have.length_of(2)