diff --git a/common/djangoapps/third_party_auth/management/commands/tests/test_data/another-testshib-providers.xml b/common/djangoapps/third_party_auth/management/commands/tests/test_data/another-testshib-providers.xml
new file mode 100644
index 0000000000..caeaf6627d
--- /dev/null
+++ b/common/djangoapps/third_party_auth/management/commands/tests/test_data/another-testshib-providers.xml
@@ -0,0 +1,379 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ testshib.org
+
+ TestShib Test IdP
+ TestShib IdP. Use this as a source of attributes
+ for your test SP.
+ https://www.testshib.org/testshibtwo.jpg
+
+
+
+
+
+
+
+
+
+
+ MIIDAzCCAeugAwIBAgIVAPX0G6LuoXnKS0Muei006mVSBXbvMA0GCSqGSIb3DQEB
+ CwUAMBsxGTAXBgNVBAMMEGlkcC50ZXN0c2hpYi5vcmcwHhcNMTYwODIzMjEyMDU0
+ WhcNMzYwODIzMjEyMDU0WjAbMRkwFwYDVQQDDBBpZHAudGVzdHNoaWIub3JnMIIB
+ IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAg9C4J2DiRTEhJAWzPt1S3ryh
+ m3M2P3hPpwJwvt2q948vdTUxhhvNMuc3M3S4WNh6JYBs53R+YmjqJAII4ShMGNEm
+ lGnSVfHorex7IxikpuDPKV3SNf28mCAZbQrX+hWA+ann/uifVzqXktOjs6DdzdBn
+ xoVhniXgC8WCJwKcx6JO/hHsH1rG/0DSDeZFpTTcZHj4S9MlLNUtt5JxRzV/MmmB
+ 3ObaX0CMqsSWUOQeE4nylSlp5RWHCnx70cs9kwz5WrflnbnzCeHU2sdbNotBEeTH
+ ot6a2cj/pXlRJIgPsrL/4VSicPZcGYMJMPoLTJ8mdy6mpR6nbCmP7dVbCIm/DQID
+ AQABoz4wPDAdBgNVHQ4EFgQUUfaDa2mPi24x09yWp1OFXmZ2GPswGwYDVR0RBBQw
+ EoIQaWRwLnRlc3RzaGliLm9yZzANBgkqhkiG9w0BAQsFAAOCAQEASKKgqTxhqBzR
+ OZ1eVy++si+eTTUQZU4+8UywSKLia2RattaAPMAcXUjO+3cYOQXLVASdlJtt+8QP
+ dRkfp8SiJemHPXC8BES83pogJPYEGJsKo19l4XFJHPnPy+Dsn3mlJyOfAa8RyWBS
+ 80u5lrvAcr2TJXt9fXgkYs7BOCigxtZoR8flceGRlAZ4p5FPPxQR6NDYb645jtOT
+ MVr3zgfjP6Wh2dt+2p04LG7ENJn8/gEwtXVuXCsPoSCDx9Y0QmyXTJNdV1aB0AhO
+ RkWPlFYwp+zOyOIR+3m1+pqWFpn0eT/HrxpdKa74FA3R2kq4R7dXe4G0kUgXTdqX
+ MLRKhDgdmA==
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ urn:mace:shibboleth:1.0:nameIdentifier
+ urn:oasis:names:tc:SAML:2.0:nameid-format:transient
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MIIDAzCCAeugAwIBAgIVAPX0G6LuoXnKS0Muei006mVSBXbvMA0GCSqGSIb3DQEB
+ CwUAMBsxGTAXBgNVBAMMEGlkcC50ZXN0c2hpYi5vcmcwHhcNMTYwODIzMjEyMDU0
+ WhcNMzYwODIzMjEyMDU0WjAbMRkwFwYDVQQDDBBpZHAudGVzdHNoaWIub3JnMIIB
+ IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAg9C4J2DiRTEhJAWzPt1S3ryh
+ m3M2P3hPpwJwvt2q948vdTUxhhvNMuc3M3S4WNh6JYBs53R+YmjqJAII4ShMGNEm
+ lGnSVfHorex7IxikpuDPKV3SNf28mCAZbQrX+hWA+ann/uifVzqXktOjs6DdzdBn
+ xoVhniXgC8WCJwKcx6JO/hHsH1rG/0DSDeZFpTTcZHj4S9MlLNUtt5JxRzV/MmmB
+ 3ObaX0CMqsSWUOQeE4nylSlp5RWHCnx70cs9kwz5WrflnbnzCeHU2sdbNotBEeTH
+ ot6a2cj/pXlRJIgPsrL/4VSicPZcGYMJMPoLTJ8mdy6mpR6nbCmP7dVbCIm/DQID
+ AQABoz4wPDAdBgNVHQ4EFgQUUfaDa2mPi24x09yWp1OFXmZ2GPswGwYDVR0RBBQw
+ EoIQaWRwLnRlc3RzaGliLm9yZzANBgkqhkiG9w0BAQsFAAOCAQEASKKgqTxhqBzR
+ OZ1eVy++si+eTTUQZU4+8UywSKLia2RattaAPMAcXUjO+3cYOQXLVASdlJtt+8QP
+ dRkfp8SiJemHPXC8BES83pogJPYEGJsKo19l4XFJHPnPy+Dsn3mlJyOfAa8RyWBS
+ 80u5lrvAcr2TJXt9fXgkYs7BOCigxtZoR8flceGRlAZ4p5FPPxQR6NDYb645jtOT
+ MVr3zgfjP6Wh2dt+2p04LG7ENJn8/gEwtXVuXCsPoSCDx9Y0QmyXTJNdV1aB0AhO
+ RkWPlFYwp+zOyOIR+3m1+pqWFpn0eT/HrxpdKa74FA3R2kq4R7dXe4G0kUgXTdqX
+ MLRKhDgdmA==
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ urn:mace:shibboleth:1.0:nameIdentifier
+ urn:oasis:names:tc:SAML:2.0:nameid-format:transient
+
+
+
+
+ TestShib Two Identity Provider
+ TestShib Two
+ http://www.testshib.org/testshib-two/
+
+
+ Nate
+ Klingenstein
+ ndk@internet2.edu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TestShib Test SP
+ TestShib SP. Log into this to test your machine.
+ Once logged in check that all attributes that you expected have been
+ released.
+ https://www.testshib.org/testshibtwo.jpg
+
+
+
+
+
+
+
+ MIIEPjCCAyagAwIBAgIBADANBgkqhkiG9w0BAQUFADB3MQswCQYDVQQGEwJVUzEV
+ MBMGA1UECBMMUGVubnN5bHZhbmlhMRMwEQYDVQQHEwpQaXR0c2J1cmdoMSIwIAYD
+ VQQKExlUZXN0U2hpYiBTZXJ2aWNlIFByb3ZpZGVyMRgwFgYDVQQDEw9zcC50ZXN0
+ c2hpYi5vcmcwHhcNMDYwODMwMjEyNDM5WhcNMTYwODI3MjEyNDM5WjB3MQswCQYD
+ VQQGEwJVUzEVMBMGA1UECBMMUGVubnN5bHZhbmlhMRMwEQYDVQQHEwpQaXR0c2J1
+ cmdoMSIwIAYDVQQKExlUZXN0U2hpYiBTZXJ2aWNlIFByb3ZpZGVyMRgwFgYDVQQD
+ Ew9zcC50ZXN0c2hpYi5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+ AQDJyR6ZP6MXkQ9z6RRziT0AuCabDd3x1m7nLO9ZRPbr0v1LsU+nnC363jO8nGEq
+ sqkgiZ/bSsO5lvjEt4ehff57ERio2Qk9cYw8XCgmYccVXKH9M+QVO1MQwErNobWb
+ AjiVkuhWcwLWQwTDBowfKXI87SA7KR7sFUymNx5z1aoRvk3GM++tiPY6u4shy8c7
+ vpWbVfisfTfvef/y+galxjPUQYHmegu7vCbjYP3On0V7/Ivzr+r2aPhp8egxt00Q
+ XpilNai12LBYV3Nv/lMsUzBeB7+CdXRVjZOHGuQ8mGqEbsj8MBXvcxIKbcpeK5Zi
+ JCVXPfarzuriM1G5y5QkKW+LAgMBAAGjgdQwgdEwHQYDVR0OBBYEFKB6wPDxwYrY
+ StNjU5P4b4AjBVQVMIGhBgNVHSMEgZkwgZaAFKB6wPDxwYrYStNjU5P4b4AjBVQV
+ oXukeTB3MQswCQYDVQQGEwJVUzEVMBMGA1UECBMMUGVubnN5bHZhbmlhMRMwEQYD
+ VQQHEwpQaXR0c2J1cmdoMSIwIAYDVQQKExlUZXN0U2hpYiBTZXJ2aWNlIFByb3Zp
+ ZGVyMRgwFgYDVQQDEw9zcC50ZXN0c2hpYi5vcmeCAQAwDAYDVR0TBAUwAwEB/zAN
+ BgkqhkiG9w0BAQUFAAOCAQEAc06Kgt7ZP6g2TIZgMbFxg6vKwvDL0+2dzF11Onpl
+ 5sbtkPaNIcj24lQ4vajCrrGKdzHXo9m54BzrdRJ7xDYtw0dbu37l1IZVmiZr12eE
+ Iay/5YMU+aWP1z70h867ZQ7/7Y4HW345rdiS6EW663oH732wSYNt9kr7/0Uer3KD
+ 9CuPuOidBacospDaFyfsaJruE99Kd6Eu/w5KLAGG+m0iqENCziDGzVA47TngKz2v
+ PVA+aokoOyoz3b53qeti77ijatSEoKjxheBWpO+eoJeGq/e49Um3M2ogIX/JAlMa
+ Inh+vYSYngQB2sx9LGkR9KHaMKNIGCDehk93Xla4pWJx1w==
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ urn:oasis:names:tc:SAML:2.0:nameid-format:transient
+ urn:mace:shibboleth:1.0:nameIdentifier
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TestShib Two Service Provider
+ TestShib Two
+ http://www.testshib.org/testshib-two/
+
+
+ Nate
+ Klingenstein
+ ndk@internet2.edu
+
+
+
+
+
+
+
diff --git a/common/djangoapps/third_party_auth/management/commands/tests/test_data/testshib-providers.xml b/common/djangoapps/third_party_auth/management/commands/tests/test_data/testshib-providers.xml
new file mode 100644
index 0000000000..9e7d4ebeb4
--- /dev/null
+++ b/common/djangoapps/third_party_auth/management/commands/tests/test_data/testshib-providers.xml
@@ -0,0 +1,379 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ testshib.org
+
+ TestShib Test IdP
+ TestShib IdP. Use this as a source of attributes
+ for your test SP.
+ https://www.testshib.org/testshibtwo.jpg
+
+
+
+
+
+
+
+
+
+
+ MIIDAzCCAeugAwIBAgIVAPX0G6LuoXnKS0Muei006mVSBXbvMA0GCSqGSIb3DQEB
+ CwUAMBsxGTAXBgNVBAMMEGlkcC50ZXN0c2hpYi5vcmcwHhcNMTYwODIzMjEyMDU0
+ WhcNMzYwODIzMjEyMDU0WjAbMRkwFwYDVQQDDBBpZHAudGVzdHNoaWIub3JnMIIB
+ IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAg9C4J2DiRTEhJAWzPt1S3ryh
+ m3M2P3hPpwJwvt2q948vdTUxhhvNMuc3M3S4WNh6JYBs53R+YmjqJAII4ShMGNEm
+ lGnSVfHorex7IxikpuDPKV3SNf28mCAZbQrX+hWA+ann/uifVzqXktOjs6DdzdBn
+ xoVhniXgC8WCJwKcx6JO/hHsH1rG/0DSDeZFpTTcZHj4S9MlLNUtt5JxRzV/MmmB
+ 3ObaX0CMqsSWUOQeE4nylSlp5RWHCnx70cs9kwz5WrflnbnzCeHU2sdbNotBEeTH
+ ot6a2cj/pXlRJIgPsrL/4VSicPZcGYMJMPoLTJ8mdy6mpR6nbCmP7dVbCIm/DQID
+ AQABoz4wPDAdBgNVHQ4EFgQUUfaDa2mPi24x09yWp1OFXmZ2GPswGwYDVR0RBBQw
+ EoIQaWRwLnRlc3RzaGliLm9yZzANBgkqhkiG9w0BAQsFAAOCAQEASKKgqTxhqBzR
+ OZ1eVy++si+eTTUQZU4+8UywSKLia2RattaAPMAcXUjO+3cYOQXLVASdlJtt+8QP
+ dRkfp8SiJemHPXC8BES83pogJPYEGJsKo19l4XFJHPnPy+Dsn3mlJyOfAa8RyWBS
+ 80u5lrvAcr2TJXt9fXgkYs7BOCigxtZoR8flceGRlAZ4p5FPPxQR6NDYb645jtOT
+ MVr3zgfjP6Wh2dt+2p04LG7ENJn8/gEwtXVuXCsPoSCDx9Y0QmyXTJNdV1aB0AhO
+ RkWPlFYwp+zOyOIR+3m1+pqWFpn0eT/HrxpdKa74FA3R2kq4R7dXe4G0kUgXTdqX
+ MLRKhDgdmA==
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ urn:mace:shibboleth:1.0:nameIdentifier
+ urn:oasis:names:tc:SAML:2.0:nameid-format:transient
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MIIDAzCCAeugAwIBAgIVAPX0G6LuoXnKS0Muei006mVSBXbvMA0GCSqGSIb3DQEB
+ CwUAMBsxGTAXBgNVBAMMEGlkcC50ZXN0c2hpYi5vcmcwHhcNMTYwODIzMjEyMDU0
+ WhcNMzYwODIzMjEyMDU0WjAbMRkwFwYDVQQDDBBpZHAudGVzdHNoaWIub3JnMIIB
+ IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAg9C4J2DiRTEhJAWzPt1S3ryh
+ m3M2P3hPpwJwvt2q948vdTUxhhvNMuc3M3S4WNh6JYBs53R+YmjqJAII4ShMGNEm
+ lGnSVfHorex7IxikpuDPKV3SNf28mCAZbQrX+hWA+ann/uifVzqXktOjs6DdzdBn
+ xoVhniXgC8WCJwKcx6JO/hHsH1rG/0DSDeZFpTTcZHj4S9MlLNUtt5JxRzV/MmmB
+ 3ObaX0CMqsSWUOQeE4nylSlp5RWHCnx70cs9kwz5WrflnbnzCeHU2sdbNotBEeTH
+ ot6a2cj/pXlRJIgPsrL/4VSicPZcGYMJMPoLTJ8mdy6mpR6nbCmP7dVbCIm/DQID
+ AQABoz4wPDAdBgNVHQ4EFgQUUfaDa2mPi24x09yWp1OFXmZ2GPswGwYDVR0RBBQw
+ EoIQaWRwLnRlc3RzaGliLm9yZzANBgkqhkiG9w0BAQsFAAOCAQEASKKgqTxhqBzR
+ OZ1eVy++si+eTTUQZU4+8UywSKLia2RattaAPMAcXUjO+3cYOQXLVASdlJtt+8QP
+ dRkfp8SiJemHPXC8BES83pogJPYEGJsKo19l4XFJHPnPy+Dsn3mlJyOfAa8RyWBS
+ 80u5lrvAcr2TJXt9fXgkYs7BOCigxtZoR8flceGRlAZ4p5FPPxQR6NDYb645jtOT
+ MVr3zgfjP6Wh2dt+2p04LG7ENJn8/gEwtXVuXCsPoSCDx9Y0QmyXTJNdV1aB0AhO
+ RkWPlFYwp+zOyOIR+3m1+pqWFpn0eT/HrxpdKa74FA3R2kq4R7dXe4G0kUgXTdqX
+ MLRKhDgdmA==
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ urn:mace:shibboleth:1.0:nameIdentifier
+ urn:oasis:names:tc:SAML:2.0:nameid-format:transient
+
+
+
+
+ TestShib Two Identity Provider
+ TestShib Two
+ http://www.testshib.org/testshib-two/
+
+
+ Nate
+ Klingenstein
+ ndk@internet2.edu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TestShib Test SP
+ TestShib SP. Log into this to test your machine.
+ Once logged in check that all attributes that you expected have been
+ released.
+ https://www.testshib.org/testshibtwo.jpg
+
+
+
+
+
+
+
+ MIIEPjCCAyagAwIBAgIBADANBgkqhkiG9w0BAQUFADB3MQswCQYDVQQGEwJVUzEV
+ MBMGA1UECBMMUGVubnN5bHZhbmlhMRMwEQYDVQQHEwpQaXR0c2J1cmdoMSIwIAYD
+ VQQKExlUZXN0U2hpYiBTZXJ2aWNlIFByb3ZpZGVyMRgwFgYDVQQDEw9zcC50ZXN0
+ c2hpYi5vcmcwHhcNMDYwODMwMjEyNDM5WhcNMTYwODI3MjEyNDM5WjB3MQswCQYD
+ VQQGEwJVUzEVMBMGA1UECBMMUGVubnN5bHZhbmlhMRMwEQYDVQQHEwpQaXR0c2J1
+ cmdoMSIwIAYDVQQKExlUZXN0U2hpYiBTZXJ2aWNlIFByb3ZpZGVyMRgwFgYDVQQD
+ Ew9zcC50ZXN0c2hpYi5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+ AQDJyR6ZP6MXkQ9z6RRziT0AuCabDd3x1m7nLO9ZRPbr0v1LsU+nnC363jO8nGEq
+ sqkgiZ/bSsO5lvjEt4ehff57ERio2Qk9cYw8XCgmYccVXKH9M+QVO1MQwErNobWb
+ AjiVkuhWcwLWQwTDBowfKXI87SA7KR7sFUymNx5z1aoRvk3GM++tiPY6u4shy8c7
+ vpWbVfisfTfvef/y+galxjPUQYHmegu7vCbjYP3On0V7/Ivzr+r2aPhp8egxt00Q
+ XpilNai12LBYV3Nv/lMsUzBeB7+CdXRVjZOHGuQ8mGqEbsj8MBXvcxIKbcpeK5Zi
+ JCVXPfarzuriM1G5y5QkKW+LAgMBAAGjgdQwgdEwHQYDVR0OBBYEFKB6wPDxwYrY
+ StNjU5P4b4AjBVQVMIGhBgNVHSMEgZkwgZaAFKB6wPDxwYrYStNjU5P4b4AjBVQV
+ oXukeTB3MQswCQYDVQQGEwJVUzEVMBMGA1UECBMMUGVubnN5bHZhbmlhMRMwEQYD
+ VQQHEwpQaXR0c2J1cmdoMSIwIAYDVQQKExlUZXN0U2hpYiBTZXJ2aWNlIFByb3Zp
+ ZGVyMRgwFgYDVQQDEw9zcC50ZXN0c2hpYi5vcmeCAQAwDAYDVR0TBAUwAwEB/zAN
+ BgkqhkiG9w0BAQUFAAOCAQEAc06Kgt7ZP6g2TIZgMbFxg6vKwvDL0+2dzF11Onpl
+ 5sbtkPaNIcj24lQ4vajCrrGKdzHXo9m54BzrdRJ7xDYtw0dbu37l1IZVmiZr12eE
+ Iay/5YMU+aWP1z70h867ZQ7/7Y4HW345rdiS6EW663oH732wSYNt9kr7/0Uer3KD
+ 9CuPuOidBacospDaFyfsaJruE99Kd6Eu/w5KLAGG+m0iqENCziDGzVA47TngKz2v
+ PVA+aokoOyoz3b53qeti77ijatSEoKjxheBWpO+eoJeGq/e49Um3M2ogIX/JAlMa
+ Inh+vYSYngQB2sx9LGkR9KHaMKNIGCDehk93Xla4pWJx1w==
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ urn:oasis:names:tc:SAML:2.0:nameid-format:transient
+ urn:mace:shibboleth:1.0:nameIdentifier
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TestShib Two Service Provider
+ TestShib Two
+ http://www.testshib.org/testshib-two/
+
+
+ Nate
+ Klingenstein
+ ndk@internet2.edu
+
+
+
+
+
+
+
diff --git a/common/djangoapps/third_party_auth/management/commands/tests/test_saml.py b/common/djangoapps/third_party_auth/management/commands/tests/test_saml.py
index 12d790bd1e..59f28f5817 100644
--- a/common/djangoapps/third_party_auth/management/commands/tests/test_saml.py
+++ b/common/djangoapps/third_party_auth/management/commands/tests/test_saml.py
@@ -3,11 +3,45 @@ Tests for `saml` management command, this command fetches saml metadata from pro
existing data accordingly.
"""
import unittest
+import os
+import mock
from django.test import TestCase
from django.core.management import call_command
from django.core.management.base import CommandError
from django.conf import settings
+from django.utils.six import StringIO
+
+from requests.models import Response
+
+from third_party_auth.tests.factories import SAMLConfigurationFactory, SAMLProviderConfigFactory
+
+
+def mock_get(status_code=200):
+ """
+ Args:
+ status_code (int): integer showing the status code for the response object.
+
+ Returns:
+ returns a function that can be used as a mock function for requests.get.
+ """
+ def _(url=None, *args, **kwargs): # pylint: disable=unused-argument
+ """
+ mock method for requests.get, this method will read xml file, form a Response object from the
+ contents of this file, set status code and return the Response object.
+ """
+ url = url.split("/")[-1] if url else "testshib-providers.xml"
+
+ file_path = os.path.dirname(os.path.realpath(__file__)) + "/test_data/{}".format(url)
+ with open(file_path) as providers:
+ xml = providers.read()
+
+ response = Response()
+ response._content = xml # pylint: disable=protected-access
+ response.status_code = status_code
+
+ return response
+ return _
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
@@ -15,6 +49,28 @@ class TestSAMLCommand(TestCase):
"""
Test django management command for fetching saml metadata.
"""
+ def setUp(self):
+ """
+ Setup operations for saml configurations. these operations contain
+ creation of SAMLConfiguration and SAMLProviderConfig records in database.
+ """
+ super(TestSAMLCommand, self).setUp()
+
+ self.stdout = StringIO()
+
+ # We are creating SAMLConfiguration instance here so that there is always at-least one
+ # disabled saml configuration instance, this is done to verify that disabled configurations are
+ # not processed.
+ SAMLConfigurationFactory.create(enabled=False)
+ SAMLProviderConfigFactory.create()
+
+ def __create_saml_configurations__(self, saml_config=None, saml_provider_config=None):
+ """
+ Helper method to create SAMLConfiguration and AMLProviderConfig.
+ """
+ SAMLConfigurationFactory.create(enabled=True, **(saml_config or {}))
+ SAMLProviderConfigFactory.create(enabled=True, **(saml_provider_config or {}))
+
def test_raises_command_error_for_invalid_arguments(self):
"""
Test that management command raises `CommandError` with a proper message in case of
@@ -29,3 +85,82 @@ class TestSAMLCommand(TestCase):
# Call `saml` command without any argument so that it raises a CommandError
with self.assertRaisesMessage(CommandError, "Command can only be used with '--pull' option."):
call_command("saml", pull=False)
+
+ def test_no_saml_configuration(self):
+ """
+ Test that management command completes without errors and logs correct information when no
+ saml configurations are enabled/present.
+ """
+ # Capture command output log for testing.
+ call_command("saml", pull=True, stdout=self.stdout)
+
+ self.assertIn('Done. Fetched 0 total. 0 were updated and 0 failed.', self.stdout.getvalue())
+
+ @mock.patch("requests.get", mock_get())
+ def test_fetch_saml_metadata(self):
+ """
+ Test that management command completes without errors and logs correct information when
+ one or more saml configurations are enabled.
+ """
+ # Create enabled configurations
+ self.__create_saml_configurations__()
+
+ # Capture command output log for testing.
+ call_command("saml", pull=True, stdout=self.stdout)
+
+ self.assertIn('Done. Fetched 1 total. 1 were updated and 0 failed.', self.stdout.getvalue())
+
+ @mock.patch("requests.get", mock_get(status_code=404))
+ def test_fetch_saml_metadata_failure(self):
+ """
+ Test that management command completes with proper message for errors
+ and logs correct information.
+ """
+ # Create enabled configurations
+ self.__create_saml_configurations__()
+
+ # Capture command output log for testing.
+ call_command("saml", pull=True, stdout=self.stdout)
+
+ self.assertIn('Done. Fetched 1 total. 0 were updated and 1 failed.', self.stdout.getvalue())
+
+ @mock.patch("requests.get", mock_get(status_code=200))
+ def test_fetch_multiple_providers_data(self):
+ """
+ Test that management command completes with proper message for error or success
+ and logs correct information when there are multiple providers with their data.
+ """
+ # Create enabled configurations
+ self.__create_saml_configurations__()
+
+ # Add another set of configurations
+ self.__create_saml_configurations__(
+ saml_config={
+ "site__domain": "second.testserver.fake",
+ },
+ saml_provider_config={
+ "site__domain": "second.testserver.fake",
+ "idp_slug": "second-test-shib",
+ "entity_id": "https://idp.testshib.org/idp/another-shibboleth",
+ "metadata_source": "https://www.testshib.org/metadata/another-testshib-providers.xml",
+ }
+ )
+
+ # Add another set of configurations
+ self.__create_saml_configurations__(
+ saml_config={
+ "site__domain": "third.testserver.fake",
+ },
+ saml_provider_config={
+ "site__domain": "third.testserver.fake",
+ "idp_slug": "third-test-shib",
+ # Note: This entity id will not be present in returned response and will cause failed update.
+ "entity_id": "https://idp.testshib.org/idp/non-existent-shibboleth",
+ "metadata_source": "https://www.testshib.org/metadata/third/testshib-providers.xml",
+ }
+ )
+
+ # Capture command output log for testing.
+ call_command("saml", pull=True, stdout=self.stdout)
+
+ self.assertIn('Done. Fetched 3 total. 2 were updated and 1 failed.', self.stdout.getvalue())
diff --git a/common/djangoapps/third_party_auth/tests/factories.py b/common/djangoapps/third_party_auth/tests/factories.py
new file mode 100644
index 0000000000..c145f2296c
--- /dev/null
+++ b/common/djangoapps/third_party_auth/tests/factories.py
@@ -0,0 +1,37 @@
+"""
+Provides factories for third_party_auth models.
+"""
+from factory import SubFactory
+from factory.django import DjangoModelFactory
+
+from third_party_auth.models import SAMLConfiguration, SAMLProviderConfig
+from openedx.core.djangoapps.site_configuration.tests.factories import SiteFactory
+
+
+class SAMLConfigurationFactory(DjangoModelFactory):
+ """
+ Factory or SAMLConfiguration model in third_party_auth app.
+ """
+ class Meta(object):
+ model = SAMLConfiguration
+
+ site = SubFactory(SiteFactory)
+ enabled = True
+
+
+class SAMLProviderConfigFactory(DjangoModelFactory):
+ """
+ Factory or SAMLProviderConfig model in third_party_auth app.
+ """
+ class Meta(object):
+ model = SAMLProviderConfig
+ django_get_or_create = ('idp_slug', 'metadata_source', "entity_id")
+
+ site = SubFactory(SiteFactory)
+
+ enabled = True
+ idp_slug = "test-shib"
+ name = "TestShib College"
+
+ entity_id = "https://idp.testshib.org/idp/shibboleth"
+ metadata_source = "https://www.testshib.org/metadata/testshib-providers.xml"
diff --git a/openedx/core/djangoapps/site_configuration/tests/factories.py b/openedx/core/djangoapps/site_configuration/tests/factories.py
index 1e2cfd6359..f9277d1a41 100644
--- a/openedx/core/djangoapps/site_configuration/tests/factories.py
+++ b/openedx/core/djangoapps/site_configuration/tests/factories.py
@@ -24,6 +24,7 @@ class SiteFactory(DjangoModelFactory):
"""
class Meta(object):
model = Site
+ django_get_or_create = ('domain',)
domain = 'testserver.fake'
name = 'testserver.fake'